338 changes: 338 additions & 0 deletions llvm/include/llvm/ObjectYAML/WasmYAML.h
Original file line number Diff line number Diff line change
@@ -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
88 changes: 83 additions & 5 deletions llvm/include/llvm/Support/Wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand All @@ -100,6 +176,8 @@ enum : unsigned {
#include "WasmRelocs/WebAssembly.def"
};

#undef WASM_RELOC

} // end namespace wasm
} // end namespace llvm

Expand Down
635 changes: 574 additions & 61 deletions llvm/lib/Object/WasmObjectFile.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions llvm/lib/ObjectYAML/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ add_llvm_library(LLVMObjectYAML
ELFYAML.cpp
MachOYAML.cpp
ObjectYAML.cpp
WasmYAML.cpp
YAML.cpp
)
3 changes: 3 additions & 0 deletions llvm/lib/ObjectYAML/ObjectYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
348 changes: 348 additions & 0 deletions llvm/lib/ObjectYAML/WasmYAML.cpp
Original file line number Diff line number Diff line change
@@ -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
72 changes: 72 additions & 0 deletions llvm/test/ObjectYAML/wasm/code_section.yaml
Original file line number Diff line number Diff line change
@@ -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
17 changes: 17 additions & 0 deletions llvm/test/ObjectYAML/wasm/custom_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
28 changes: 28 additions & 0 deletions llvm/test/ObjectYAML/wasm/data_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
42 changes: 42 additions & 0 deletions llvm/test/ObjectYAML/wasm/elem_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
27 changes: 27 additions & 0 deletions llvm/test/ObjectYAML/wasm/export_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
19 changes: 19 additions & 0 deletions llvm/test/ObjectYAML/wasm/function_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
25 changes: 25 additions & 0 deletions llvm/test/ObjectYAML/wasm/global_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
9 changes: 9 additions & 0 deletions llvm/test/ObjectYAML/wasm/header.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
--- !WASM
FileHeader:
Version: 0x00000001
...
# CHECK: --- !WASM
# CHECK: FileHeader:
# CHECK: Version: 0x00000001
# CHECK: ...
8 changes: 8 additions & 0 deletions llvm/test/ObjectYAML/wasm/header_invalid_version.yaml
Original file line number Diff line number Diff line change
@@ -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'
41 changes: 41 additions & 0 deletions llvm/test/ObjectYAML/wasm/import_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
23 changes: 23 additions & 0 deletions llvm/test/ObjectYAML/wasm/memory_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
15 changes: 15 additions & 0 deletions llvm/test/ObjectYAML/wasm/start_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
25 changes: 25 additions & 0 deletions llvm/test/ObjectYAML/wasm/table_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
33 changes: 33 additions & 0 deletions llvm/test/ObjectYAML/wasm/type_section.yaml
Original file line number Diff line number Diff line change
@@ -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: ...
Binary file modified llvm/test/tools/llvm-objdump/Inputs/test.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-objdump/wasm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Binary file modified llvm/test/tools/llvm-readobj/Inputs/trivial.obj.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-readobj/sections.test
Original file line number Diff line number Diff line change
Expand Up @@ -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: }
Expand Down
14 changes: 7 additions & 7 deletions llvm/tools/llvm-readobj/WasmDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ class WasmDumper : public ObjDumper {
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);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions llvm/tools/obj2yaml/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ add_llvm_tool(obj2yaml
dwarf2yaml.cpp
elf2yaml.cpp
macho2yaml.cpp
wasm2yaml.cpp
Error.cpp
)
2 changes: 2 additions & 0 deletions llvm/tools/obj2yaml/obj2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 3 additions & 0 deletions llvm/tools/obj2yaml/obj2yaml.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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 {
Expand Down
219 changes: 219 additions & 0 deletions llvm/tools/obj2yaml/wasm2yaml.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
1 change: 1 addition & 0 deletions llvm/tools/yaml2obj/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ add_llvm_tool(yaml2obj
yaml2coff.cpp
yaml2elf.cpp
yaml2macho.cpp
yaml2wasm.cpp
)
2 changes: 2 additions & 0 deletions llvm/tools/yaml2obj/yaml2obj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
5 changes: 5 additions & 0 deletions llvm/tools/yaml2obj/yaml2obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ namespace ELFYAML {
struct Object;
}

namespace WasmYAML {
struct Object;
}

namespace yaml {
class Input;
struct YamlObjectFile;
Expand All @@ -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
377 changes: 377 additions & 0 deletions llvm/tools/yaml2obj/yaml2wasm.cpp
Original file line number Diff line number Diff line change
@@ -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);
}