[WebAssembly] Improve support for WebAssembly binary format

Mostly this change adds support converting to and from
YAML which will allow us to write more test cases for
the WebAssembly MC and lld ports.

Better support for objdump, readelf, and nm will be in
followup CLs.

I had to update the two wasm test binaries because they
used the old style 'name' section which is no longer
supported.

Differential Revision: https://reviews.llvm.org/D31099

Patch by Sam Clegg

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@299101 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Derek Schuff 2017-03-30 19:44:09 +00:00
parent 38ad05a6a6
commit 349a48fadd
35 changed files with 2443 additions and 86 deletions

View File

@ -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<uint8_t> Content; // Section content
std::vector<wasm::WasmRelocation> 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<wasm::WasmSignature>& types() const { return Signatures; }
const std::vector<uint32_t>& functionTypes() const { return FunctionTypes; }
const std::vector<wasm::WasmImport>& imports() const { return Imports; }
const std::vector<wasm::WasmTable>& tables() const { return Tables; }
const std::vector<wasm::WasmLimits>& memories() const { return Memories; }
const std::vector<wasm::WasmGlobal>& globals() const { return Globals; }
const std::vector<wasm::WasmExport>& exports() const { return Exports; }
const std::vector<wasm::WasmElemSegment>& elements() const {
return ElemSegments;
}
const std::vector<wasm::WasmDataSegment>& dataSegments() const {
return DataSegments;
}
const std::vector<wasm::WasmFunction>& functions() const { return Functions; }
const ArrayRef<uint8_t>& 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 @@ protected:
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 @@ protected:
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<wasm::WasmSection> Sections;
std::vector<WasmSection> Sections;
std::vector<wasm::WasmSignature> Signatures;
std::vector<uint32_t> FunctionTypes;
std::vector<wasm::WasmTable> Tables;
std::vector<wasm::WasmLimits> Memories;
std::vector<wasm::WasmGlobal> Globals;
std::vector<wasm::WasmImport> Imports;
std::vector<wasm::WasmExport> Exports;
std::vector<wasm::WasmElemSegment> ElemSegments;
std::vector<wasm::WasmDataSegment> DataSegments;
std::vector<WasmSymbol> Symbols;
std::vector<wasm::WasmFunction> Functions;
ArrayRef<uint8_t> CodeSection;
uint32_t StartFunction;
};
} // end namespace object

View File

@ -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 @@ struct YamlObjectFile {
std::unique_ptr<COFFYAML::Object> Coff;
std::unique_ptr<MachOYAML::Object> MachO;
std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
std::unique_ptr<WasmYAML::Object> Wasm;
};
template <> struct MappingTraits<YamlObjectFile> {

View File

@ -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<uint32_t> Functions;
};
struct Global {
ValueType Type;
bool Mutable;
wasm::WasmInitExpr InitExpr;
};
struct LocalDecl {
ValueType Type;
uint32_t Count;
};
struct Function {
std::vector<LocalDecl> 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<ValueType> ParamTypes;
ValueType ReturnType;
};
struct Section {
Section(SectionType SecType) : Type(SecType) {}
SectionType Type;
std::vector<Relocation> 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<Signature> 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<Import> 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<uint32_t> 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<Table> 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<Limits> 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<Global> 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<Export> 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<ElemSegment> 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<Function> 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<DataSegment> Segments;
};
struct Object {
FileHeader Header;
std::vector<std::unique_ptr<Section>> Sections;
};
} // end namespace WasmYAML
} // end namespace llvm
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::WasmYAML::Section>)
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<WasmYAML::FileHeader> {
static void mapping(IO &IO, WasmYAML::FileHeader &FileHdr);
};
template <> struct MappingTraits<std::unique_ptr<WasmYAML::Section>> {
static void mapping(IO &IO, std::unique_ptr<WasmYAML::Section> &Section);
};
template <> struct MappingTraits<WasmYAML::Object> {
static void mapping(IO &IO, WasmYAML::Object &Object);
};
template <> struct MappingTraits<WasmYAML::Import> {
static void mapping(IO &IO, WasmYAML::Import &Import);
};
template <> struct MappingTraits<WasmYAML::Export> {
static void mapping(IO &IO, WasmYAML::Export &Export);
};
template <> struct MappingTraits<WasmYAML::Global> {
static void mapping(IO &IO, WasmYAML::Global &Global);
};
template <> struct ScalarEnumerationTraits<WasmYAML::SectionType> {
static void enumeration(IO &IO, WasmYAML::SectionType &Type);
};
template <> struct MappingTraits<WasmYAML::Signature> {
static void mapping(IO &IO, WasmYAML::Signature &Signature);
};
template <> struct MappingTraits<WasmYAML::Table> {
static void mapping(IO &IO, WasmYAML::Table &Table);
};
template <> struct MappingTraits<WasmYAML::Limits> {
static void mapping(IO &IO, WasmYAML::Limits &Limits);
};
template <> struct MappingTraits<WasmYAML::Function> {
static void mapping(IO &IO, WasmYAML::Function &Function);
};
template <> struct MappingTraits<WasmYAML::Relocation> {
static void mapping(IO &IO, WasmYAML::Relocation &Relocation);
};
template <> struct MappingTraits<WasmYAML::LocalDecl> {
static void mapping(IO &IO, WasmYAML::LocalDecl &LocalDecl);
};
template <> struct MappingTraits<wasm::WasmInitExpr> {
static void mapping(IO &IO, wasm::WasmInitExpr &Expr);
};
template <> struct MappingTraits<WasmYAML::DataSegment> {
static void mapping(IO &IO, WasmYAML::DataSegment &Segment);
};
template <> struct MappingTraits<WasmYAML::ElemSegment> {
static void mapping(IO &IO, WasmYAML::ElemSegment &Segment);
};
template <> struct ScalarEnumerationTraits<WasmYAML::ValueType> {
static void enumeration(IO &IO, WasmYAML::ValueType &Type);
};
template <> struct ScalarEnumerationTraits<WasmYAML::ExportKind> {
static void enumeration(IO &IO, WasmYAML::ExportKind &Kind);
};
template <> struct ScalarEnumerationTraits<WasmYAML::TableType> {
static void enumeration(IO &IO, WasmYAML::TableType &Type);
};
template <> struct ScalarEnumerationTraits<WasmYAML::Opcode> {
static void enumeration(IO &IO, WasmYAML::Opcode &Opcode);
};
template <> struct ScalarEnumerationTraits<WasmYAML::RelocType> {
static void enumeration(IO &IO, WasmYAML::RelocType &Kind);
};
} // end namespace yaml
} // end namespace llvm
#endif

View File

@ -30,11 +30,83 @@ struct WasmObjectHeader {
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<uint8_t> Content; // Section content
struct WasmSignature {
std::vector<int32_t> 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<WasmLocalDecl> Locals;
ArrayRef<uint8_t> Body;
};
struct WasmDataSegment {
uint32_t Index;
WasmInitExpr Offset;
ArrayRef<uint8_t> Content;
};
struct WasmElemSegment {
uint32_t TableIndex;
WasmInitExpr Offset;
std::vector<uint32_t> 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 @@ enum : unsigned {
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 @@ enum : unsigned {
#include "WasmRelocs/WebAssembly.def"
};
#undef WASM_RELOC
} // end namespace wasm
} // end namespace llvm

View File

@ -38,12 +38,33 @@ ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
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 @@ static StringRef readString(const uint8_t *&Ptr) {
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<GenericBinaryError>("Invalid opcode in init_expr",
object_error::parse_failed);
}
uint8_t EndOpcode = readOpcode(Ptr);
if (EndOpcode != wasm::WASM_OPCODE_END) {
return make_error<GenericBinaryError>("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<StringError>("Zero length section",
object_error::parse_failed);
@ -73,7 +180,7 @@ static Error readSection(wasm::WasmSection &Section, const uint8_t *&Ptr,
}
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 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
}
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<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>("Bad relocation type",
object_error::parse_failed);
}
Section->Relocations.push_back(Reloc);
}
if (Ptr != End)
return make_error<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>(
"Multiple return types not supported", object_error::parse_failed);
}
Sig.ReturnType = readVarint7(Ptr);
}
Signatures.push_back(Sig);
}
if (Ptr != End)
return make_error<GenericBinaryError>("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<GenericBinaryError>(
"Unexpected import kind", object_error::parse_failed);
}
Imports.push_back(Im);
}
if (Ptr != End)
return make_error<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>("Invalid table element type",
object_error::parse_failed);
}
Table.Limits = readLimits(Ptr);
Tables.push_back(Table);
}
if (Ptr != End)
return make_error<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>(
"Unexpected export kind", object_error::parse_failed);
}
}
if (Ptr != End)
return make_error<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>("Invalid function count",
object_error::parse_failed);
}
CodeSection = ArrayRef<uint8_t>(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<uint8_t>(Ptr, BodySize);
Ptr += BodySize;
assert(Ptr == FunctionEnd);
Functions.push_back(Function);
}
if (Ptr != End)
return make_error<GenericBinaryError>("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<GenericBinaryError>("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<GenericBinaryError>("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<uint8_t>(Ptr, Size);
Ptr += Size;
DataSegments.push_back(Segment);
}
if (Ptr != End)
return make_error<GenericBinaryError>("Data section ended prematurely",
object_error::parse_failed);
return Error::success();
}
@ -117,37 +593,47 @@ 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_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<StringRef> 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<uint64_t> 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 @@ 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];
const WasmSection &S = Sections[Sec.d.a];
#define ECase(X) \
case wasm::WASM_SEC_##X: \
Res = #X; \
@ -211,13 +697,13 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
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<const char *>(S.Content.data()),
@ -234,13 +720,11 @@ bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
}
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::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_begin(DataRefImpl Ref) const {
DataRefImpl RelocRef;
RelocRef.d.a = Ref.d.a;
RelocRef.d.b = 0;
return relocation_iterator(RelocationRef(RelocRef, this));
}
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);
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 @@ symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
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<char> &Result) const {
llvm_unreachable("not yet implemented");
DataRefImpl Ref, SmallVectorImpl<char> &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 @@ SubtargetFeatures WasmObjectFile::getFeatures() const {
bool WasmObjectFile::isRelocatableObject() const { return false; }
const wasm::WasmSection *
WasmObjectFile::getWasmSection(const SectionRef &Section) const {
return &Sections[Section.getRawDataRefImpl().d.a];
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 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];
}

View File

@ -6,5 +6,6 @@ add_llvm_library(LLVMObjectYAML
ELFYAML.cpp
MachOYAML.cpp
ObjectYAML.cpp
WasmYAML.cpp
YAML.cpp
)

View File

@ -43,6 +43,9 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
ObjectFile.FatMachO.reset(new MachOYAML::UniversalBinary());
MappingTraits<MachOYAML::UniversalBinary>::mapping(IO,
*ObjectFile.FatMachO);
} else if (IO.mapTag("!WASM")) {
ObjectFile.Wasm.reset(new WasmYAML::Object());
MappingTraits<WasmYAML::Object>::mapping(IO, *ObjectFile.Wasm);
} else {
Input &In = (Input &)IO;
std::string Tag = In.getCurrentNode()->getRawTag();

348
lib/ObjectYAML/WasmYAML.cpp Normal file
View File

@ -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<WasmYAML::FileHeader>::mapping(
IO &IO, WasmYAML::FileHeader &FileHdr) {
IO.mapRequired("Version", FileHdr.Version);
}
void MappingTraits<WasmYAML::Object>::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<std::unique_ptr<WasmYAML::Section>>::mapping(
IO &IO, std::unique_ptr<WasmYAML::Section> &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<WasmYAML::CustomSection>(Section.get()));
break;
case wasm::WASM_SEC_TYPE:
if (!IO.outputting())
Section.reset(new WasmYAML::TypeSection());
sectionMapping(IO, *cast<WasmYAML::TypeSection>(Section.get()));
break;
case wasm::WASM_SEC_IMPORT:
if (!IO.outputting())
Section.reset(new WasmYAML::ImportSection());
sectionMapping(IO, *cast<WasmYAML::ImportSection>(Section.get()));
break;
case wasm::WASM_SEC_FUNCTION:
if (!IO.outputting())
Section.reset(new WasmYAML::FunctionSection());
sectionMapping(IO, *cast<WasmYAML::FunctionSection>(Section.get()));
break;
case wasm::WASM_SEC_TABLE:
if (!IO.outputting())
Section.reset(new WasmYAML::TableSection());
sectionMapping(IO, *cast<WasmYAML::TableSection>(Section.get()));
break;
case wasm::WASM_SEC_MEMORY:
if (!IO.outputting())
Section.reset(new WasmYAML::MemorySection());
sectionMapping(IO, *cast<WasmYAML::MemorySection>(Section.get()));
break;
case wasm::WASM_SEC_GLOBAL:
if (!IO.outputting())
Section.reset(new WasmYAML::GlobalSection());
sectionMapping(IO, *cast<WasmYAML::GlobalSection>(Section.get()));
break;
case wasm::WASM_SEC_EXPORT:
if (!IO.outputting())
Section.reset(new WasmYAML::ExportSection());
sectionMapping(IO, *cast<WasmYAML::ExportSection>(Section.get()));
break;
case wasm::WASM_SEC_START:
if (!IO.outputting())
Section.reset(new WasmYAML::StartSection());
sectionMapping(IO, *cast<WasmYAML::StartSection>(Section.get()));
break;
case wasm::WASM_SEC_ELEM:
if (!IO.outputting())
Section.reset(new WasmYAML::ElemSection());
sectionMapping(IO, *cast<WasmYAML::ElemSection>(Section.get()));
break;
case wasm::WASM_SEC_CODE:
if (!IO.outputting())
Section.reset(new WasmYAML::CodeSection());
sectionMapping(IO, *cast<WasmYAML::CodeSection>(Section.get()));
break;
case wasm::WASM_SEC_DATA:
if (!IO.outputting())
Section.reset(new WasmYAML::DataSection());
sectionMapping(IO, *cast<WasmYAML::DataSection>(Section.get()));
break;
default:
llvm_unreachable("Unknown section type");
}
}
void ScalarEnumerationTraits<WasmYAML::SectionType>::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<WasmYAML::Signature>::mapping(
IO &IO, WasmYAML::Signature &Signature) {
IO.mapOptional("Index", Signature.Index);
IO.mapRequired("ReturnType", Signature.ReturnType);
IO.mapRequired("ParamTypes", Signature.ParamTypes);
}
void MappingTraits<WasmYAML::Table>::mapping(IO &IO, WasmYAML::Table &Table) {
IO.mapRequired("ElemType", Table.ElemType);
IO.mapRequired("Limits", Table.TableLimits);
}
void MappingTraits<WasmYAML::Function>::mapping(IO &IO,
WasmYAML::Function &Function) {
IO.mapRequired("Locals", Function.Locals);
IO.mapRequired("Body", Function.Body);
}
void MappingTraits<WasmYAML::Relocation>::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<WasmYAML::LocalDecl>::mapping(
IO &IO, WasmYAML::LocalDecl &LocalDecl) {
IO.mapRequired("Type", LocalDecl.Type);
IO.mapRequired("Count", LocalDecl.Count);
}
void MappingTraits<WasmYAML::Limits>::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<WasmYAML::ElemSegment>::mapping(
IO &IO, WasmYAML::ElemSegment &Segment) {
IO.mapRequired("Offset", Segment.Offset);
IO.mapRequired("Functions", Segment.Functions);
}
void MappingTraits<WasmYAML::Import>::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<WasmYAML::Export>::mapping(IO &IO,
WasmYAML::Export &Export) {
IO.mapRequired("Name", Export.Name);
IO.mapRequired("Kind", Export.Kind);
IO.mapRequired("Index", Export.Index);
}
void MappingTraits<WasmYAML::Global>::mapping(IO &IO,
WasmYAML::Global &Global) {
IO.mapRequired("Type", Global.Type);
IO.mapRequired("Mutable", Global.Mutable);
IO.mapRequired("InitExpr", Global.InitExpr);
}
void MappingTraits<wasm::WasmInitExpr>::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<WasmYAML::DataSegment>::mapping(
IO &IO, WasmYAML::DataSegment &Segment) {
IO.mapRequired("Index", Segment.Index);
IO.mapRequired("Offset", Segment.Offset);
IO.mapRequired("Content", Segment.Content);
}
void ScalarEnumerationTraits<WasmYAML::ValueType>::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<WasmYAML::ExportKind>::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<WasmYAML::Opcode>::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<WasmYAML::TableType>::enumeration(
IO &IO, WasmYAML::TableType &Type) {
#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X);
ECase(ANYFUNC);
#undef ECase
}
void ScalarEnumerationTraits<WasmYAML::RelocType>::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

View File

@ -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

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -0,0 +1,9 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
--- !WASM
FileHeader:
Version: 0x00000001
...
# CHECK: --- !WASM
# CHECK: FileHeader:
# CHECK: Version: 0x00000001
# CHECK: ...

View File

@ -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'

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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

View File

@ -531,7 +531,7 @@ WASM-NEXT: Offset: 75
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: }

View File

@ -55,14 +55,14 @@ public:
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);
}
}
}

View File

@ -11,5 +11,6 @@ add_llvm_tool(obj2yaml
dwarf2yaml.cpp
elf2yaml.cpp
macho2yaml.cpp
wasm2yaml.cpp
Error.cpp
)

View File

@ -24,6 +24,8 @@ static std::error_code dumpObject(const ObjectFile &Obj) {
return coff2yaml(outs(), cast<COFFObjectFile>(Obj));
if (Obj.isELF())
return elf2yaml(outs(), Obj);
if (Obj.isWasm())
return wasm2yaml(outs(), cast<WasmObjectFile>(Obj));
return obj2yaml_error::unsupported_obj_file_format;
}

View File

@ -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 <system_error>
@ -23,6 +24,8 @@ std::error_code elf2yaml(llvm::raw_ostream &Out,
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 {

View File

@ -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<WasmYAML::Object *> dump();
};
ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
auto Y = make_unique<WasmYAML::Object>();
// 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<WasmYAML::Section> 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<WasmYAML::CustomSection>();
CustomSec->Name = WasmSec.Name;
CustomSec->Payload = yaml::BinaryRef(WasmSec.Content);
S = std::move(CustomSec);
break;
}
case wasm::WASM_SEC_TYPE: {
auto TypeSec = make_unique<WasmYAML::TypeSection>();
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<WasmYAML::ImportSection>();
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<WasmYAML::FunctionSection>();
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<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 = std::move(TableSec);
break;
}
case wasm::WASM_SEC_MEMORY: {
auto MemorySec = make_unique<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 = std::move(MemorySec);
break;
}
case wasm::WASM_SEC_GLOBAL: {
auto GlobalSec = make_unique<WasmYAML::GlobalSection>();
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<WasmYAML::StartSection>();
StartSec->StartFunction = Obj.startFunction();
S = std::move(StartSec);
break;
}
case wasm::WASM_SEC_EXPORT: {
auto ExportSec = make_unique<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 = std::move(ExportSec);
break;
}
case wasm::WASM_SEC_ELEM: {
auto ElemSec = make_unique<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 = std::move(ElemSec);
break;
}
case wasm::WASM_SEC_CODE: {
auto CodeSec = make_unique<WasmYAML::CodeSection>();
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<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 = 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<WasmYAML::Object *> YAMLOrErr = Dumper.dump();
if (std::error_code EC = YAMLOrErr.getError())
return EC;
std::unique_ptr<WasmYAML::Object> YAML(YAMLOrErr.get());
yaml::Output Yout(Out);
Yout << *YAML;
return std::error_code();
}

View File

@ -10,4 +10,5 @@ add_llvm_tool(yaml2obj
yaml2coff.cpp
yaml2elf.cpp
yaml2macho.cpp
yaml2wasm.cpp
)

View File

@ -57,6 +57,8 @@ static int convertYAML(yaml::Input &YIn, raw_ostream &Out) {
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;
}

View File

@ -23,6 +23,10 @@ namespace ELFYAML {
struct Object;
}
namespace WasmYAML {
struct Object;
}
namespace yaml {
class Input;
struct YamlObjectFile;
@ -32,5 +36,6 @@ struct YamlObjectFile;
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

View File

@ -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<WasmYAML::Section> &Sec : Obj.Sections) {
encodeULEB128(Sec->Type, OS);
std::string OutString;
raw_string_ostream StringStream(OutString);
if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::TypeSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::ImportSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::FunctionSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::TableSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::MemorySection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::StartSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::ElemSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::CodeSection>(Sec.get())) {
if (auto Err = writeSectionContent(StringStream, *S))
return Err;
} else if (auto S = dyn_cast<WasmYAML::DataSection>(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<WasmYAML::Section> &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);
}