summaryrefslogtreecommitdiff
path: root/tools/yaml2obj
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
commit71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch)
tree5343938942df402b49ec7300a1c25a2d4ccd5821 /tools/yaml2obj
parent31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff)
Diffstat (limited to 'tools/yaml2obj')
-rw-r--r--tools/yaml2obj/CMakeLists.txt2
-rw-r--r--tools/yaml2obj/yaml2dwarf.cpp330
-rw-r--r--tools/yaml2obj/yaml2macho.cpp32
-rw-r--r--tools/yaml2obj/yaml2obj.cpp28
-rw-r--r--tools/yaml2obj/yaml2obj.h16
-rw-r--r--tools/yaml2obj/yaml2wasm.cpp377
6 files changed, 420 insertions, 365 deletions
diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt
index 5e726496003f..a885547598d8 100644
--- a/tools/yaml2obj/CMakeLists.txt
+++ b/tools/yaml2obj/CMakeLists.txt
@@ -8,7 +8,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(yaml2obj
yaml2obj.cpp
yaml2coff.cpp
- yaml2dwarf.cpp
yaml2elf.cpp
yaml2macho.cpp
+ yaml2wasm.cpp
)
diff --git a/tools/yaml2obj/yaml2dwarf.cpp b/tools/yaml2obj/yaml2dwarf.cpp
deleted file mode 100644
index 3ceb7772b969..000000000000
--- a/tools/yaml2obj/yaml2dwarf.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-//===- yaml2dwarf - Convert YAML to DWARF binary data ---------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief The DWARF component of yaml2obj.
-///
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ObjectYAML/DWARFYAML.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/SwapByteOrder.h"
-
-#include <algorithm>
-
-using namespace llvm;
-
-template <typename T>
-void writeInteger(T Integer, raw_ostream &OS, bool IsLittleEndian) {
- if (IsLittleEndian != sys::IsLittleEndianHost)
- sys::swapByteOrder(Integer);
- OS.write(reinterpret_cast<char *>(&Integer), sizeof(T));
-}
-
-void writeVariableSizedInteger(uint64_t Integer, size_t Size, raw_ostream &OS,
- bool IsLittleEndian) {
- if (8 == Size)
- writeInteger((uint64_t)Integer, OS, IsLittleEndian);
- else if (4 == Size)
- writeInteger((uint32_t)Integer, OS, IsLittleEndian);
- else if (2 == Size)
- writeInteger((uint16_t)Integer, OS, IsLittleEndian);
- else if (1 == Size)
- writeInteger((uint8_t)Integer, OS, IsLittleEndian);
- else
- assert(false && "Invalid integer write size.");
-}
-
-void ZeroFillBytes(raw_ostream &OS, size_t Size) {
- std::vector<uint8_t> FillData;
- FillData.insert(FillData.begin(), Size, 0);
- OS.write(reinterpret_cast<char *>(FillData.data()), Size);
-}
-
-void yaml2debug_str(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (auto Str : DI.DebugStrings) {
- OS.write(Str.data(), Str.size());
- OS.write('\0');
- }
-}
-
-void yaml2debug_abbrev(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (auto AbbrevDecl : DI.AbbrevDecls) {
- encodeULEB128(AbbrevDecl.Code, OS);
- encodeULEB128(AbbrevDecl.Tag, OS);
- OS.write(AbbrevDecl.Children);
- for (auto Attr : AbbrevDecl.Attributes) {
- encodeULEB128(Attr.Attribute, OS);
- encodeULEB128(Attr.Form, OS);
- }
- encodeULEB128(0, OS);
- encodeULEB128(0, OS);
- }
-}
-
-void yaml2debug_aranges(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (auto Range : DI.ARanges) {
- auto HeaderStart = OS.tell();
- writeInteger((uint32_t)Range.Length, OS, DI.IsLittleEndian);
- writeInteger((uint16_t)Range.Version, OS, DI.IsLittleEndian);
- writeInteger((uint32_t)Range.CuOffset, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)Range.AddrSize, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)Range.SegSize, OS, DI.IsLittleEndian);
-
- auto HeaderSize = OS.tell() - HeaderStart;
- auto FirstDescriptor = alignTo(HeaderSize, Range.AddrSize * 2);
- ZeroFillBytes(OS, FirstDescriptor - HeaderSize);
-
- for (auto Descriptor : Range.Descriptors) {
- writeVariableSizedInteger(Descriptor.Address, Range.AddrSize, OS,
- DI.IsLittleEndian);
- writeVariableSizedInteger(Descriptor.Length, Range.AddrSize, OS,
- DI.IsLittleEndian);
- }
- ZeroFillBytes(OS, Range.AddrSize * 2);
- }
-}
-
-void yaml2pubsection(raw_ostream &OS, const DWARFYAML::PubSection &Sect,
- bool IsLittleEndian) {
- writeInteger((uint32_t)Sect.Length, OS, IsLittleEndian);
- writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian);
- writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian);
- writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian);
- for (auto Entry : Sect.Entries) {
- writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian);
- if (Sect.IsGNUStyle)
- writeInteger((uint32_t)Entry.Descriptor, OS, IsLittleEndian);
- OS.write(Entry.Name.data(), Entry.Name.size());
- OS.write('\0');
- }
-}
-
-void yaml2debug_info(raw_ostream &OS, const DWARFYAML::Data &DI) {
-
- for (auto CU : DI.CompileUnits) {
- writeInteger((uint32_t)CU.Length, OS, DI.IsLittleEndian);
- writeInteger((uint16_t)CU.Version, OS, DI.IsLittleEndian);
- writeInteger((uint32_t)CU.AbbrOffset, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)CU.AddrSize, OS, DI.IsLittleEndian);
-
- auto FirstAbbrevCode = CU.Entries[0].AbbrCode;
-
- for (auto Entry : CU.Entries) {
- encodeULEB128(Entry.AbbrCode, OS);
- if (Entry.AbbrCode == 0u)
- continue;
- bool Indirect = false;
- assert(Entry.AbbrCode - FirstAbbrevCode < DI.AbbrevDecls.size() &&
- "Out of range AbbCode");
- auto &Abbrev = DI.AbbrevDecls[Entry.AbbrCode - FirstAbbrevCode];
-
- auto FormVal = Entry.Values.begin();
- auto AbbrForm = Abbrev.Attributes.begin();
- for (;
- FormVal != Entry.Values.end() && AbbrForm != Abbrev.Attributes.end();
- ++FormVal, ++AbbrForm) {
- dwarf::Form Form = AbbrForm->Form;
- do {
- Indirect = false;
- switch (Form) {
- case dwarf::DW_FORM_addr:
- writeVariableSizedInteger(FormVal->Value, CU.AddrSize, OS,
- DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_ref_addr: {
- // TODO: Handle DWARF32/DWARF64 after Line Table data is done
- auto writeSize = CU.Version == 2 ? CU.AddrSize : 4;
- writeVariableSizedInteger(FormVal->Value, writeSize, OS,
- DI.IsLittleEndian);
- break;
- }
- case dwarf::DW_FORM_exprloc:
- case dwarf::DW_FORM_block:
- encodeULEB128(FormVal->BlockData.size(), OS);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- case dwarf::DW_FORM_block1: {
- auto writeSize = FormVal->BlockData.size();
- writeInteger((uint8_t)writeSize, OS, DI.IsLittleEndian);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- }
- case dwarf::DW_FORM_block2: {
- auto writeSize = FormVal->BlockData.size();
- writeInteger((uint16_t)writeSize, OS, DI.IsLittleEndian);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- }
- case dwarf::DW_FORM_block4: {
- auto writeSize = FormVal->BlockData.size();
- writeInteger((uint32_t)writeSize, OS, DI.IsLittleEndian);
- OS.write(reinterpret_cast<char *>(&FormVal->BlockData[0]),
- FormVal->BlockData.size());
- break;
- }
- case dwarf::DW_FORM_data1:
- case dwarf::DW_FORM_ref1:
- case dwarf::DW_FORM_flag:
- writeInteger((uint8_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_data2:
- case dwarf::DW_FORM_ref2:
- writeInteger((uint16_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_data4:
- case dwarf::DW_FORM_ref4:
- writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_data8:
- case dwarf::DW_FORM_ref8:
- writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_sdata:
- encodeSLEB128(FormVal->Value, OS);
- break;
- case dwarf::DW_FORM_udata:
- case dwarf::DW_FORM_ref_udata:
- encodeULEB128(FormVal->Value, OS);
- break;
- case dwarf::DW_FORM_string:
- OS.write(FormVal->CStr.data(), FormVal->CStr.size());
- OS.write('\0');
- break;
- case dwarf::DW_FORM_indirect:
- encodeULEB128(FormVal->Value, OS);
- Indirect = true;
- Form = static_cast<dwarf::Form>((uint64_t)FormVal->Value);
- ++FormVal;
- break;
- case dwarf::DW_FORM_strp:
- case dwarf::DW_FORM_sec_offset:
- case dwarf::DW_FORM_GNU_ref_alt:
- case dwarf::DW_FORM_GNU_strp_alt:
- case dwarf::DW_FORM_line_strp:
- case dwarf::DW_FORM_strp_sup:
- case dwarf::DW_FORM_ref_sup:
- // TODO: Handle DWARF32/64
- writeInteger((uint32_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_ref_sig8:
- writeInteger((uint64_t)FormVal->Value, OS, DI.IsLittleEndian);
- break;
- case dwarf::DW_FORM_GNU_addr_index:
- case dwarf::DW_FORM_GNU_str_index:
- encodeULEB128(FormVal->Value, OS);
- break;
- default:
- break;
- }
- } while (Indirect);
- }
- }
- }
-}
-
-void yaml2FileEntry(raw_ostream &OS, const DWARFYAML::File &File) {
- OS.write(File.Name.data(), File.Name.size());
- OS.write('\0');
- encodeULEB128(File.DirIdx, OS);
- encodeULEB128(File.ModTime, OS);
- encodeULEB128(File.Length, OS);
-}
-
-void yaml2debug_line(raw_ostream &OS, const DWARFYAML::Data &DI) {
- for (const auto LineTable : DI.DebugLines) {
- writeInteger((uint32_t)LineTable.TotalLength, OS, DI.IsLittleEndian);
- uint64_t SizeOfPrologueLength = 4;
- if (LineTable.TotalLength == UINT32_MAX) {
- writeInteger((uint64_t)LineTable.TotalLength64, OS, DI.IsLittleEndian);
- SizeOfPrologueLength = 8;
- }
- writeInteger((uint16_t)LineTable.Version, OS, DI.IsLittleEndian);
- writeVariableSizedInteger(LineTable.PrologueLength, SizeOfPrologueLength,
- OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.MinInstLength, OS, DI.IsLittleEndian);
- if (LineTable.Version >= 4)
- writeInteger((uint8_t)LineTable.MaxOpsPerInst, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.DefaultIsStmt, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.LineBase, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.LineRange, OS, DI.IsLittleEndian);
- writeInteger((uint8_t)LineTable.OpcodeBase, OS, DI.IsLittleEndian);
-
- for (auto OpcodeLength : LineTable.StandardOpcodeLengths)
- writeInteger((uint8_t)OpcodeLength, OS, DI.IsLittleEndian);
-
- for (auto IncludeDir : LineTable.IncludeDirs) {
- OS.write(IncludeDir.data(), IncludeDir.size());
- OS.write('\0');
- }
- OS.write('\0');
-
- for (auto File : LineTable.Files)
- yaml2FileEntry(OS, File);
- OS.write('\0');
-
- for (auto Op : LineTable.Opcodes) {
- writeInteger((uint8_t)Op.Opcode, OS, DI.IsLittleEndian);
- if (Op.Opcode == 0) {
- encodeULEB128(Op.ExtLen, OS);
- writeInteger((uint8_t)Op.SubOpcode, OS, DI.IsLittleEndian);
- switch (Op.SubOpcode) {
- case dwarf::DW_LNE_set_address:
- case dwarf::DW_LNE_set_discriminator:
- writeVariableSizedInteger(Op.Data, DI.CompileUnits[0].AddrSize, OS,
- DI.IsLittleEndian);
- break;
- case dwarf::DW_LNE_define_file:
- yaml2FileEntry(OS, Op.FileEntry);
- break;
- case dwarf::DW_LNE_end_sequence:
- break;
- default:
- for (auto OpByte : Op.UnknownOpcodeData)
- writeInteger((uint8_t)OpByte, OS, DI.IsLittleEndian);
- }
- } else if (Op.Opcode < LineTable.OpcodeBase) {
- switch (Op.Opcode) {
- case dwarf::DW_LNS_copy:
- case dwarf::DW_LNS_negate_stmt:
- case dwarf::DW_LNS_set_basic_block:
- case dwarf::DW_LNS_const_add_pc:
- case dwarf::DW_LNS_set_prologue_end:
- case dwarf::DW_LNS_set_epilogue_begin:
- break;
-
- case dwarf::DW_LNS_advance_pc:
- case dwarf::DW_LNS_set_file:
- case dwarf::DW_LNS_set_column:
- case dwarf::DW_LNS_set_isa:
- encodeULEB128(Op.Data, OS);
- break;
-
- case dwarf::DW_LNS_advance_line:
- encodeSLEB128(Op.SData, OS);
- break;
-
- case dwarf::DW_LNS_fixed_advance_pc:
- writeInteger((uint16_t)Op.Data, OS, DI.IsLittleEndian);
- break;
-
- default:
- for (auto OpData : Op.StandardOpcodeData) {
- encodeULEB128(OpData, OS);
- }
- }
- }
- }
- }
-}
diff --git a/tools/yaml2obj/yaml2macho.cpp b/tools/yaml2obj/yaml2macho.cpp
index cbc4d7ff50d5..92b736e5298e 100644
--- a/tools/yaml2obj/yaml2macho.cpp
+++ b/tools/yaml2obj/yaml2macho.cpp
@@ -14,6 +14,7 @@
#include "yaml2obj.h"
#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/ObjectYAML/DWARFEmitter.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
@@ -179,6 +180,21 @@ size_t writeLoadCommandData<MachO::rpath_command>(MachOYAML::LoadCommand &LC,
return writePayloadString(LC, OS);
}
+template <>
+size_t writeLoadCommandData<MachO::build_version_command>(
+ MachOYAML::LoadCommand &LC, raw_ostream &OS, bool IsLittleEndian) {
+ size_t BytesWritten = 0;
+ for (const auto &T : LC.Tools) {
+ struct MachO::build_tool_version tool = T;
+ if (IsLittleEndian != sys::IsLittleEndianHost)
+ MachO::swapStruct(tool);
+ OS.write(reinterpret_cast<const char *>(&tool),
+ sizeof(MachO::build_tool_version));
+ BytesWritten += sizeof(MachO::build_tool_version);
+ }
+ return BytesWritten;
+}
+
void ZeroFillBytes(raw_ostream &OS, size_t Size) {
std::vector<uint8_t> FillData;
FillData.insert(FillData.begin(), Size, 0);
@@ -269,19 +285,21 @@ Error MachOWriter::writeSectionData(raw_ostream &OS) {
"Wrote too much data somewhere, section offsets don't line up.");
if (0 == strncmp(&Sec.segname[0], "__DWARF", 16)) {
if (0 == strncmp(&Sec.sectname[0], "__debug_str", 16)) {
- yaml2debug_str(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugStr(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_abbrev", 16)) {
- yaml2debug_abbrev(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugAbbrev(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_aranges", 16)) {
- yaml2debug_aranges(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugAranges(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_pubnames", 16)) {
- yaml2pubsection(OS, Obj.DWARF.PubNames, Obj.IsLittleEndian);
+ DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubNames,
+ Obj.IsLittleEndian);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_pubtypes", 16)) {
- yaml2pubsection(OS, Obj.DWARF.PubTypes, Obj.IsLittleEndian);
+ DWARFYAML::EmitPubSection(OS, Obj.DWARF.PubTypes,
+ Obj.IsLittleEndian);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_info", 16)) {
- yaml2debug_info(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugInfo(OS, Obj.DWARF);
} else if (0 == strncmp(&Sec.sectname[0], "__debug_line", 16)) {
- yaml2debug_line(OS, Obj.DWARF);
+ DWARFYAML::EmitDebugLine(OS, Obj.DWARF);
}
} else {
// Fills section data with 0xDEADBEEF
diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp
index f746d84a3898..e64e3dc1d179 100644
--- a/tools/yaml2obj/yaml2obj.cpp
+++ b/tools/yaml2obj/yaml2obj.cpp
@@ -40,31 +40,33 @@ DocNum("docnum", cl::init(1),
static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
cl::value_desc("filename"));
+LLVM_ATTRIBUTE_NORETURN static void error(Twine Message) {
+ errs() << Message << "\n";
+ exit(1);
+}
+
static int convertYAML(yaml::Input &YIn, raw_ostream &Out) {
unsigned CurDocNum = 0;
do {
if (++CurDocNum == DocNum) {
yaml::YamlObjectFile Doc;
YIn >> Doc;
- if (YIn.error()) {
- errs() << "yaml2obj: Failed to parse YAML file!\n";
- return 1;
- }
-
+ if (YIn.error())
+ error("yaml2obj: Failed to parse YAML file!");
if (Doc.Elf)
return yaml2elf(*Doc.Elf, Out);
if (Doc.Coff)
return yaml2coff(*Doc.Coff, Out);
if (Doc.MachO || Doc.FatMachO)
return yaml2macho(Doc, Out);
- errs() << "yaml2obj: Unknown document type!\n";
- return 1;
+ if (Doc.Wasm)
+ return yaml2wasm(*Doc.Wasm, Out);
+ error("yaml2obj: Unknown document type!");
}
} while (YIn.nextDocument());
- errs() << "yaml2obj: Cannot find the " << DocNum
- << llvm::getOrdinalSuffix(DocNum) << " document\n";
- return 1;
+ error("yaml2obj: Cannot find the " + utostr(DocNum) +
+ llvm::getOrdinalSuffix(DocNum) + " document");
}
int main(int argc, char **argv) {
@@ -79,10 +81,8 @@ int main(int argc, char **argv) {
std::error_code EC;
std::unique_ptr<tool_output_file> Out(
new tool_output_file(OutputFilename, EC, sys::fs::F_None));
- if (EC) {
- errs() << EC.message() << '\n';
- return 1;
- }
+ if (EC)
+ error("yaml2obj: Error opening '" + OutputFilename + "': " + EC.message());
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
MemoryBuffer::getFileOrSTDIN(Input);
diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h
index 4a637366e1a1..cb8f11904916 100644
--- a/tools/yaml2obj/yaml2obj.h
+++ b/tools/yaml2obj/yaml2obj.h
@@ -23,9 +23,8 @@ namespace ELFYAML {
struct Object;
}
-namespace DWARFYAML {
-struct Data;
-struct PubSection;
+namespace WasmYAML {
+struct Object;
}
namespace yaml {
@@ -37,15 +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);
-
-void yaml2debug_abbrev(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-void yaml2debug_str(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-
-void yaml2debug_aranges(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-void yaml2pubsection(llvm::raw_ostream &OS,
- const llvm::DWARFYAML::PubSection &Sect,
- bool IsLittleEndian);
-void yaml2debug_info(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
-void yaml2debug_line(llvm::raw_ostream &OS, const llvm::DWARFYAML::Data &DI);
+int yaml2wasm(llvm::WasmYAML::Object &Doc, llvm::raw_ostream &Out);
#endif
diff --git a/tools/yaml2obj/yaml2wasm.cpp b/tools/yaml2obj/yaml2wasm.cpp
new file mode 100644
index 000000000000..55267ce0392d
--- /dev/null
+++ b/tools/yaml2obj/yaml2wasm.cpp
@@ -0,0 +1,377 @@
+//===- yaml2wasm - Convert YAML to a Wasm object file --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief The Wasm component of yaml2obj.
+///
+//===----------------------------------------------------------------------===//
+//
+#include "yaml2obj.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/ObjectYAML/ObjectYAML.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+
+/// This parses a yaml stream that represents a Wasm object file.
+/// See docs/yaml2obj for the yaml scheema.
+class WasmWriter {
+public:
+ WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {}
+ int writeWasm(raw_ostream &OS);
+ int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::ImportSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::FunctionSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section);
+ int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section);
+
+private:
+ WasmYAML::Object &Obj;
+};
+
+static int writeUint64(raw_ostream &OS, uint64_t Value) {
+ char Data[sizeof(Value)];
+ support::endian::write64le(Data, Value);
+ OS.write(Data, sizeof(Data));
+ return 0;
+}
+
+static int writeUint32(raw_ostream &OS, uint32_t Value) {
+ char Data[sizeof(Value)];
+ support::endian::write32le(Data, Value);
+ OS.write(Data, sizeof(Data));
+ return 0;
+}
+
+static int writeUint8(raw_ostream &OS, uint8_t Value) {
+ char Data[sizeof(Value)];
+ memcpy(Data, &Value, sizeof(Data));
+ OS.write(Data, sizeof(Data));
+ return 0;
+}
+
+static int writeStringRef(StringRef &Str, raw_ostream &OS) {
+ encodeULEB128(Str.size(), OS);
+ OS << Str;
+ return 0;
+}
+
+static int writeLimits(WasmYAML::Limits Lim, raw_ostream &OS) {
+ encodeULEB128(Lim.Flags, OS);
+ encodeULEB128(Lim.Initial, OS);
+ if (Lim.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
+ encodeULEB128(Lim.Maximum, OS);
+ return 0;
+}
+
+static int writeInitExpr(wasm::WasmInitExpr InitExpr, raw_ostream &OS) {
+ writeUint8(OS, InitExpr.Opcode);
+ switch (InitExpr.Opcode) {
+ case wasm::WASM_OPCODE_I32_CONST:
+ encodeSLEB128(InitExpr.Value.Int32, OS);
+ break;
+ case wasm::WASM_OPCODE_I64_CONST:
+ encodeSLEB128(InitExpr.Value.Int64, OS);
+ break;
+ case wasm::WASM_OPCODE_F32_CONST:
+ writeUint32(OS, InitExpr.Value.Float32);
+ break;
+ case wasm::WASM_OPCODE_F64_CONST:
+ writeUint64(OS, InitExpr.Value.Float64);
+ break;
+ case wasm::WASM_OPCODE_GET_GLOBAL:
+ encodeULEB128(InitExpr.Value.Global, OS);
+ break;
+ default:
+ errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode;
+ return 1;
+ }
+ writeUint8(OS, wasm::WASM_OPCODE_END);
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::CustomSection &Section) {
+ // writeStringRef(Section.Name, OS);
+ // encodeULEB128(Section.Payload.binary_size(), OS);
+ Section.Payload.writeAsBinary(OS);
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::TypeSection &Section) {
+ encodeULEB128(Section.Signatures.size(), OS);
+ for (auto &Sig : Section.Signatures) {
+ encodeSLEB128(Sig.Form, OS);
+ encodeULEB128(Sig.ParamTypes.size(), OS);
+ for (auto ParamType : Sig.ParamTypes)
+ encodeSLEB128(ParamType, OS);
+ if (Sig.ReturnType == wasm::WASM_TYPE_NORESULT) {
+ encodeSLEB128(0, OS);
+ } else {
+ encodeULEB128(1, OS);
+ encodeSLEB128(Sig.ReturnType, OS);
+ }
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::ImportSection &Section) {
+ encodeULEB128(Section.Imports.size(), OS);
+ for (auto &Import : Section.Imports) {
+ writeStringRef(Import.Module, OS);
+ writeStringRef(Import.Field, OS);
+ encodeULEB128(Import.Kind, OS);
+ switch (Import.Kind) {
+ case wasm::WASM_EXTERNAL_FUNCTION:
+ encodeULEB128(Import.SigIndex, OS);
+ break;
+ case wasm::WASM_EXTERNAL_GLOBAL:
+ encodeSLEB128(Import.GlobalType, OS);
+ writeUint8(OS, Import.GlobalMutable);
+ break;
+ default:
+ errs() << "Unknown import type: " << Import.Kind;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::FunctionSection &Section) {
+ encodeULEB128(Section.FunctionTypes.size(), OS);
+ for (uint32_t FuncType : Section.FunctionTypes) {
+ encodeULEB128(FuncType, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::ExportSection &Section) {
+ encodeULEB128(Section.Exports.size(), OS);
+ for (auto &Export : Section.Exports) {
+ writeStringRef(Export.Name, OS);
+ encodeULEB128(Export.Kind, OS);
+ encodeULEB128(Export.Index, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::StartSection &Section) {
+ encodeULEB128(Section.StartFunction, OS);
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::TableSection &Section) {
+ encodeULEB128(Section.Tables.size(), OS);
+ for (auto &Table : Section.Tables) {
+ encodeSLEB128(Table.ElemType, OS);
+ writeLimits(Table.TableLimits, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::MemorySection &Section) {
+ encodeULEB128(Section.Memories.size(), OS);
+ for (auto &Mem : Section.Memories) {
+ writeLimits(Mem, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::GlobalSection &Section) {
+ encodeULEB128(Section.Globals.size(), OS);
+ for (auto &Global : Section.Globals) {
+ encodeSLEB128(Global.Type, OS);
+ writeUint8(OS, Global.Mutable);
+ writeInitExpr(Global.InitExpr, OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::ElemSection &Section) {
+ encodeULEB128(Section.Segments.size(), OS);
+ for (auto &Segment : Section.Segments) {
+ encodeULEB128(Segment.TableIndex, OS);
+ writeInitExpr(Segment.Offset, OS);
+
+ encodeULEB128(Segment.Functions.size(), OS);
+ for (auto &Function : Segment.Functions) {
+ encodeULEB128(Function, OS);
+ }
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::CodeSection &Section) {
+ encodeULEB128(Section.Functions.size(), OS);
+ for (auto &Func : Section.Functions) {
+ std::string OutString;
+ raw_string_ostream StringStream(OutString);
+
+ encodeULEB128(Func.Locals.size(), StringStream);
+ for (auto &LocalDecl : Func.Locals) {
+ encodeULEB128(LocalDecl.Count, StringStream);
+ encodeSLEB128(LocalDecl.Type, StringStream);
+ }
+
+ Func.Body.writeAsBinary(StringStream);
+
+ // Write the section size followed by the content
+ StringStream.flush();
+ encodeULEB128(OutString.size(), OS);
+ OS << OutString;
+ }
+ return 0;
+}
+
+int WasmWriter::writeSectionContent(raw_ostream &OS,
+ WasmYAML::DataSection &Section) {
+ encodeULEB128(Section.Segments.size(), OS);
+ for (auto &Segment : Section.Segments) {
+ encodeULEB128(Segment.Index, OS);
+ writeInitExpr(Segment.Offset, OS);
+ encodeULEB128(Segment.Content.binary_size(), OS);
+ Segment.Content.writeAsBinary(OS);
+ }
+ return 0;
+}
+
+int WasmWriter::writeRelocSection(raw_ostream &OS,
+ WasmYAML::Section &Sec) {
+ StringRef Name;
+ switch (Sec.Type) {
+ case wasm::WASM_SEC_CODE:
+ Name = "reloc.CODE";
+ break;
+ case wasm::WASM_SEC_DATA:
+ Name = "reloc.DATA";
+ break;
+ default:
+ llvm_unreachable("not yet implemented");
+ return 1;
+ }
+
+ writeStringRef(Name, OS);
+ encodeULEB128(Sec.Type, OS);
+ encodeULEB128(Sec.Relocations.size(), OS);
+
+ for (auto Reloc: Sec.Relocations) {
+ encodeULEB128(Reloc.Type, OS);
+ encodeULEB128(Reloc.Offset, OS);
+ encodeULEB128(Reloc.Index, OS);
+ switch (Reloc.Type) {
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
+ case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
+ encodeULEB128(Reloc.Addend, OS);
+ }
+ }
+ return 0;
+}
+
+
+int WasmWriter::writeWasm(raw_ostream &OS) {
+ // Write headers
+ OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
+ writeUint32(OS, Obj.Header.Version);
+
+ // Write each section
+ for (const std::unique_ptr<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);
+}