1 //===- yaml2wasm - Convert YAML to a Wasm object file --------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// The Wasm component of yaml2obj.
12 ///
13 //===----------------------------------------------------------------------===//
14 //
15
16 #include "llvm/ObjectYAML/ObjectYAML.h"
17 #include "llvm/Support/Endian.h"
18 #include "llvm/Support/LEB128.h"
19
20 using namespace llvm;
21
22 /// This parses a yaml stream that represents a Wasm object file.
23 /// See docs/yaml2obj for the yaml scheema.
24 class WasmWriter {
25 public:
WasmWriter(WasmYAML::Object & Obj)26 WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {}
27 int writeWasm(raw_ostream &OS);
28
29 private:
30 int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
31 uint32_t SectionIndex);
32
33 int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section);
34 int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section);
35 int writeSectionContent(raw_ostream &OS, WasmYAML::ImportSection &Section);
36 int writeSectionContent(raw_ostream &OS, WasmYAML::FunctionSection &Section);
37 int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section);
38 int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section);
39 int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section);
40 int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section);
41 int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section);
42 int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
43 int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section);
44 int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section);
45
46 // Custom section types
47 int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section);
48 int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section);
49 WasmYAML::Object &Obj;
50 uint32_t NumImportedFunctions = 0;
51 uint32_t NumImportedGlobals = 0;
52 };
53
writeUint64(raw_ostream & OS,uint64_t Value)54 static int writeUint64(raw_ostream &OS, uint64_t Value) {
55 char Data[sizeof(Value)];
56 support::endian::write64le(Data, Value);
57 OS.write(Data, sizeof(Data));
58 return 0;
59 }
60
writeUint32(raw_ostream & OS,uint32_t Value)61 static int writeUint32(raw_ostream &OS, uint32_t Value) {
62 char Data[sizeof(Value)];
63 support::endian::write32le(Data, Value);
64 OS.write(Data, sizeof(Data));
65 return 0;
66 }
67
writeUint8(raw_ostream & OS,uint8_t Value)68 static int writeUint8(raw_ostream &OS, uint8_t Value) {
69 char Data[sizeof(Value)];
70 memcpy(Data, &Value, sizeof(Data));
71 OS.write(Data, sizeof(Data));
72 return 0;
73 }
74
writeStringRef(const StringRef & Str,raw_ostream & OS)75 static int writeStringRef(const StringRef &Str, raw_ostream &OS) {
76 encodeULEB128(Str.size(), OS);
77 OS << Str;
78 return 0;
79 }
80
writeLimits(const WasmYAML::Limits & Lim,raw_ostream & OS)81 static int writeLimits(const WasmYAML::Limits &Lim, raw_ostream &OS) {
82 writeUint8(OS, Lim.Flags);
83 encodeULEB128(Lim.Initial, OS);
84 if (Lim.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
85 encodeULEB128(Lim.Maximum, OS);
86 return 0;
87 }
88
writeInitExpr(const wasm::WasmInitExpr & InitExpr,raw_ostream & OS)89 static int writeInitExpr(const wasm::WasmInitExpr &InitExpr, raw_ostream &OS) {
90 writeUint8(OS, InitExpr.Opcode);
91 switch (InitExpr.Opcode) {
92 case wasm::WASM_OPCODE_I32_CONST:
93 encodeSLEB128(InitExpr.Value.Int32, OS);
94 break;
95 case wasm::WASM_OPCODE_I64_CONST:
96 encodeSLEB128(InitExpr.Value.Int64, OS);
97 break;
98 case wasm::WASM_OPCODE_F32_CONST:
99 writeUint32(OS, InitExpr.Value.Float32);
100 break;
101 case wasm::WASM_OPCODE_F64_CONST:
102 writeUint64(OS, InitExpr.Value.Float64);
103 break;
104 case wasm::WASM_OPCODE_GET_GLOBAL:
105 encodeULEB128(InitExpr.Value.Global, OS);
106 break;
107 default:
108 errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode << "\n";
109 return 1;
110 }
111 writeUint8(OS, wasm::WASM_OPCODE_END);
112 return 0;
113 }
114
115 class SubSectionWriter {
116 raw_ostream &OS;
117 std::string OutString;
118 raw_string_ostream StringStream;
119
120 public:
SubSectionWriter(raw_ostream & OS)121 SubSectionWriter(raw_ostream &OS) : OS(OS), StringStream(OutString) {}
122
Done()123 void Done() {
124 StringStream.flush();
125 encodeULEB128(OutString.size(), OS);
126 OS << OutString;
127 OutString.clear();
128 }
129
GetStream()130 raw_ostream& GetStream() {
131 return StringStream;
132 }
133 };
134
writeSectionContent(raw_ostream & OS,WasmYAML::LinkingSection & Section)135 int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section) {
136 writeStringRef(Section.Name, OS);
137 encodeULEB128(Section.Version, OS);
138
139 SubSectionWriter SubSection(OS);
140
141 // SYMBOL_TABLE subsection
142 if (Section.SymbolTable.size()) {
143 writeUint8(OS, wasm::WASM_SYMBOL_TABLE);
144
145 encodeULEB128(Section.SymbolTable.size(), SubSection.GetStream());
146 #ifndef NDEBUG
147 uint32_t SymbolIndex = 0;
148 #endif
149 for (const WasmYAML::SymbolInfo &Info : Section.SymbolTable) {
150 assert(Info.Index == SymbolIndex++);
151 writeUint8(SubSection.GetStream(), Info.Kind);
152 encodeULEB128(Info.Flags, SubSection.GetStream());
153 switch (Info.Kind) {
154 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
155 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
156 encodeULEB128(Info.ElementIndex, SubSection.GetStream());
157 if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0)
158 writeStringRef(Info.Name, SubSection.GetStream());
159 break;
160 case wasm::WASM_SYMBOL_TYPE_DATA:
161 writeStringRef(Info.Name, SubSection.GetStream());
162 if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
163 encodeULEB128(Info.DataRef.Segment, SubSection.GetStream());
164 encodeULEB128(Info.DataRef.Offset, SubSection.GetStream());
165 encodeULEB128(Info.DataRef.Size, SubSection.GetStream());
166 }
167 break;
168 case wasm::WASM_SYMBOL_TYPE_SECTION:
169 encodeULEB128(Info.ElementIndex, SubSection.GetStream());
170 break;
171 default:
172 llvm_unreachable("unexpected kind");
173 }
174 }
175
176 SubSection.Done();
177 }
178
179 // SEGMENT_NAMES subsection
180 if (Section.SegmentInfos.size()) {
181 writeUint8(OS, wasm::WASM_SEGMENT_INFO);
182 encodeULEB128(Section.SegmentInfos.size(), SubSection.GetStream());
183 for (const WasmYAML::SegmentInfo &SegmentInfo : Section.SegmentInfos) {
184 writeStringRef(SegmentInfo.Name, SubSection.GetStream());
185 encodeULEB128(SegmentInfo.Alignment, SubSection.GetStream());
186 encodeULEB128(SegmentInfo.Flags, SubSection.GetStream());
187 }
188 SubSection.Done();
189 }
190
191 // INIT_FUNCS subsection
192 if (Section.InitFunctions.size()) {
193 writeUint8(OS, wasm::WASM_INIT_FUNCS);
194 encodeULEB128(Section.InitFunctions.size(), SubSection.GetStream());
195 for (const WasmYAML::InitFunction &Func : Section.InitFunctions) {
196 encodeULEB128(Func.Priority, SubSection.GetStream());
197 encodeULEB128(Func.Symbol, SubSection.GetStream());
198 }
199 SubSection.Done();
200 }
201
202 // COMDAT_INFO subsection
203 if (Section.Comdats.size()) {
204 writeUint8(OS, wasm::WASM_COMDAT_INFO);
205 encodeULEB128(Section.Comdats.size(), SubSection.GetStream());
206 for (const auto &C : Section.Comdats) {
207 writeStringRef(C.Name, SubSection.GetStream());
208 encodeULEB128(0, SubSection.GetStream()); // flags for future use
209 encodeULEB128(C.Entries.size(), SubSection.GetStream());
210 for (const WasmYAML::ComdatEntry &Entry : C.Entries) {
211 writeUint8(SubSection.GetStream(), Entry.Kind);
212 encodeULEB128(Entry.Index, SubSection.GetStream());
213 }
214 }
215 SubSection.Done();
216 }
217
218 return 0;
219 }
220
writeSectionContent(raw_ostream & OS,WasmYAML::NameSection & Section)221 int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section) {
222 writeStringRef(Section.Name, OS);
223 if (Section.FunctionNames.size()) {
224 writeUint8(OS, wasm::WASM_NAMES_FUNCTION);
225
226 SubSectionWriter SubSection(OS);
227
228 encodeULEB128(Section.FunctionNames.size(), SubSection.GetStream());
229 for (const WasmYAML::NameEntry &NameEntry : Section.FunctionNames) {
230 encodeULEB128(NameEntry.Index, SubSection.GetStream());
231 writeStringRef(NameEntry.Name, SubSection.GetStream());
232 }
233
234 SubSection.Done();
235 }
236 return 0;
237 }
238
writeSectionContent(raw_ostream & OS,WasmYAML::CustomSection & Section)239 int WasmWriter::writeSectionContent(raw_ostream &OS,
240 WasmYAML::CustomSection &Section) {
241 if (auto S = dyn_cast<WasmYAML::NameSection>(&Section)) {
242 if (auto Err = writeSectionContent(OS, *S))
243 return Err;
244 } else if (auto S = dyn_cast<WasmYAML::LinkingSection>(&Section)) {
245 if (auto Err = writeSectionContent(OS, *S))
246 return Err;
247 } else {
248 writeStringRef(Section.Name, OS);
249 Section.Payload.writeAsBinary(OS);
250 }
251 return 0;
252 }
253
writeSectionContent(raw_ostream & OS,WasmYAML::TypeSection & Section)254 int WasmWriter::writeSectionContent(raw_ostream &OS,
255 WasmYAML::TypeSection &Section) {
256 encodeULEB128(Section.Signatures.size(), OS);
257 uint32_t ExpectedIndex = 0;
258 for (const WasmYAML::Signature &Sig : Section.Signatures) {
259 if (Sig.Index != ExpectedIndex) {
260 errs() << "Unexpected type index: " << Sig.Index << "\n";
261 return 1;
262 }
263 ++ExpectedIndex;
264 writeUint8(OS, Sig.Form);
265 encodeULEB128(Sig.ParamTypes.size(), OS);
266 for (auto ParamType : Sig.ParamTypes)
267 writeUint8(OS, ParamType);
268 if (Sig.ReturnType == wasm::WASM_TYPE_NORESULT) {
269 encodeULEB128(0, OS);
270 } else {
271 encodeULEB128(1, OS);
272 writeUint8(OS, Sig.ReturnType);
273 }
274 }
275 return 0;
276 }
277
writeSectionContent(raw_ostream & OS,WasmYAML::ImportSection & Section)278 int WasmWriter::writeSectionContent(raw_ostream &OS,
279 WasmYAML::ImportSection &Section) {
280 encodeULEB128(Section.Imports.size(), OS);
281 for (const WasmYAML::Import &Import : Section.Imports) {
282 writeStringRef(Import.Module, OS);
283 writeStringRef(Import.Field, OS);
284 writeUint8(OS, Import.Kind);
285 switch (Import.Kind) {
286 case wasm::WASM_EXTERNAL_FUNCTION:
287 encodeULEB128(Import.SigIndex, OS);
288 NumImportedFunctions++;
289 break;
290 case wasm::WASM_EXTERNAL_GLOBAL:
291 writeUint8(OS, Import.GlobalImport.Type);
292 writeUint8(OS, Import.GlobalImport.Mutable);
293 NumImportedGlobals++;
294 break;
295 case wasm::WASM_EXTERNAL_MEMORY:
296 writeLimits(Import.Memory, OS);
297 break;
298 case wasm::WASM_EXTERNAL_TABLE:
299 writeUint8(OS,Import.TableImport.ElemType);
300 writeLimits(Import.TableImport.TableLimits, OS);
301 break;
302 default:
303 errs() << "Unknown import type: " << Import.Kind << "\n";
304 return 1;
305 }
306 }
307 return 0;
308 }
309
writeSectionContent(raw_ostream & OS,WasmYAML::FunctionSection & Section)310 int WasmWriter::writeSectionContent(raw_ostream &OS,
311 WasmYAML::FunctionSection &Section) {
312 encodeULEB128(Section.FunctionTypes.size(), OS);
313 for (uint32_t FuncType : Section.FunctionTypes) {
314 encodeULEB128(FuncType, OS);
315 }
316 return 0;
317 }
318
writeSectionContent(raw_ostream & OS,WasmYAML::ExportSection & Section)319 int WasmWriter::writeSectionContent(raw_ostream &OS,
320 WasmYAML::ExportSection &Section) {
321 encodeULEB128(Section.Exports.size(), OS);
322 for (const WasmYAML::Export &Export : Section.Exports) {
323 writeStringRef(Export.Name, OS);
324 writeUint8(OS, Export.Kind);
325 encodeULEB128(Export.Index, OS);
326 }
327 return 0;
328 }
329
writeSectionContent(raw_ostream & OS,WasmYAML::StartSection & Section)330 int WasmWriter::writeSectionContent(raw_ostream &OS,
331 WasmYAML::StartSection &Section) {
332 encodeULEB128(Section.StartFunction, OS);
333 return 0;
334 }
335
writeSectionContent(raw_ostream & OS,WasmYAML::TableSection & Section)336 int WasmWriter::writeSectionContent(raw_ostream &OS,
337 WasmYAML::TableSection &Section) {
338 encodeULEB128(Section.Tables.size(), OS);
339 for (auto &Table : Section.Tables) {
340 writeUint8(OS, Table.ElemType);
341 writeLimits(Table.TableLimits, OS);
342 }
343 return 0;
344 }
345
writeSectionContent(raw_ostream & OS,WasmYAML::MemorySection & Section)346 int WasmWriter::writeSectionContent(raw_ostream &OS,
347 WasmYAML::MemorySection &Section) {
348 encodeULEB128(Section.Memories.size(), OS);
349 for (const WasmYAML::Limits &Mem : Section.Memories) {
350 writeLimits(Mem, OS);
351 }
352 return 0;
353 }
354
writeSectionContent(raw_ostream & OS,WasmYAML::GlobalSection & Section)355 int WasmWriter::writeSectionContent(raw_ostream &OS,
356 WasmYAML::GlobalSection &Section) {
357 encodeULEB128(Section.Globals.size(), OS);
358 uint32_t ExpectedIndex = NumImportedGlobals;
359 for (auto &Global : Section.Globals) {
360 if (Global.Index != ExpectedIndex) {
361 errs() << "Unexpected global index: " << Global.Index << "\n";
362 return 1;
363 }
364 ++ExpectedIndex;
365 writeUint8(OS, Global.Type);
366 writeUint8(OS, Global.Mutable);
367 writeInitExpr(Global.InitExpr, OS);
368 }
369 return 0;
370 }
371
writeSectionContent(raw_ostream & OS,WasmYAML::ElemSection & Section)372 int WasmWriter::writeSectionContent(raw_ostream &OS,
373 WasmYAML::ElemSection &Section) {
374 encodeULEB128(Section.Segments.size(), OS);
375 for (auto &Segment : Section.Segments) {
376 encodeULEB128(Segment.TableIndex, OS);
377 writeInitExpr(Segment.Offset, OS);
378
379 encodeULEB128(Segment.Functions.size(), OS);
380 for (auto &Function : Segment.Functions) {
381 encodeULEB128(Function, OS);
382 }
383 }
384 return 0;
385 }
386
writeSectionContent(raw_ostream & OS,WasmYAML::CodeSection & Section)387 int WasmWriter::writeSectionContent(raw_ostream &OS,
388 WasmYAML::CodeSection &Section) {
389 encodeULEB128(Section.Functions.size(), OS);
390 uint32_t ExpectedIndex = NumImportedFunctions;
391 for (auto &Func : Section.Functions) {
392 std::string OutString;
393 raw_string_ostream StringStream(OutString);
394 if (Func.Index != ExpectedIndex) {
395 errs() << "Unexpected function index: " << Func.Index << "\n";
396 return 1;
397 }
398 ++ExpectedIndex;
399
400 encodeULEB128(Func.Locals.size(), StringStream);
401 for (auto &LocalDecl : Func.Locals) {
402 encodeULEB128(LocalDecl.Count, StringStream);
403 writeUint8(StringStream, LocalDecl.Type);
404 }
405
406 Func.Body.writeAsBinary(StringStream);
407
408 // Write the section size followed by the content
409 StringStream.flush();
410 encodeULEB128(OutString.size(), OS);
411 OS << OutString;
412 }
413 return 0;
414 }
415
writeSectionContent(raw_ostream & OS,WasmYAML::DataSection & Section)416 int WasmWriter::writeSectionContent(raw_ostream &OS,
417 WasmYAML::DataSection &Section) {
418 encodeULEB128(Section.Segments.size(), OS);
419 for (auto &Segment : Section.Segments) {
420 encodeULEB128(Segment.MemoryIndex, OS);
421 writeInitExpr(Segment.Offset, OS);
422 encodeULEB128(Segment.Content.binary_size(), OS);
423 Segment.Content.writeAsBinary(OS);
424 }
425 return 0;
426 }
427
writeRelocSection(raw_ostream & OS,WasmYAML::Section & Sec,uint32_t SectionIndex)428 int WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
429 uint32_t SectionIndex) {
430 switch (Sec.Type) {
431 case wasm::WASM_SEC_CODE:
432 writeStringRef("reloc.CODE", OS);
433 break;
434 case wasm::WASM_SEC_DATA:
435 writeStringRef("reloc.DATA", OS);
436 break;
437 case wasm::WASM_SEC_CUSTOM: {
438 auto CustomSection = dyn_cast<WasmYAML::CustomSection>(&Sec);
439 if (!CustomSection->Name.startswith(".debug_")) {
440 llvm_unreachable("not yet implemented (only for debug sections)");
441 return 1;
442 }
443
444 writeStringRef(("reloc." + CustomSection->Name).str(), OS);
445 break;
446 }
447 default:
448 llvm_unreachable("not yet implemented");
449 return 1;
450 }
451
452 encodeULEB128(SectionIndex, OS);
453 encodeULEB128(Sec.Relocations.size(), OS);
454
455 for (auto Reloc: Sec.Relocations) {
456 writeUint8(OS, Reloc.Type);
457 encodeULEB128(Reloc.Offset, OS);
458 encodeULEB128(Reloc.Index, OS);
459 switch (Reloc.Type) {
460 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
461 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
462 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
463 case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
464 case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
465 encodeULEB128(Reloc.Addend, OS);
466 }
467 }
468 return 0;
469 }
470
471
writeWasm(raw_ostream & OS)472 int WasmWriter::writeWasm(raw_ostream &OS) {
473 // Write headers
474 OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
475 writeUint32(OS, Obj.Header.Version);
476
477 // Write each section
478 uint32_t LastType = 0;
479 for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
480 uint32_t Type = Sec->Type;
481 if (Type != wasm::WASM_SEC_CUSTOM) {
482 if (Type < LastType) {
483 errs() << "Out of order section type: " << Type << "\n";
484 return 1;
485 }
486 LastType = Type;
487 }
488
489 encodeULEB128(Sec->Type, OS);
490 std::string OutString;
491 raw_string_ostream StringStream(OutString);
492 if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get())) {
493 if (auto Err = writeSectionContent(StringStream, *S))
494 return Err;
495 } else if (auto S = dyn_cast<WasmYAML::TypeSection>(Sec.get())) {
496 if (auto Err = writeSectionContent(StringStream, *S))
497 return Err;
498 } else if (auto S = dyn_cast<WasmYAML::ImportSection>(Sec.get())) {
499 if (auto Err = writeSectionContent(StringStream, *S))
500 return Err;
501 } else if (auto S = dyn_cast<WasmYAML::FunctionSection>(Sec.get())) {
502 if (auto Err = writeSectionContent(StringStream, *S))
503 return Err;
504 } else if (auto S = dyn_cast<WasmYAML::TableSection>(Sec.get())) {
505 if (auto Err = writeSectionContent(StringStream, *S))
506 return Err;
507 } else if (auto S = dyn_cast<WasmYAML::MemorySection>(Sec.get())) {
508 if (auto Err = writeSectionContent(StringStream, *S))
509 return Err;
510 } else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) {
511 if (auto Err = writeSectionContent(StringStream, *S))
512 return Err;
513 } else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) {
514 if (auto Err = writeSectionContent(StringStream, *S))
515 return Err;
516 } else if (auto S = dyn_cast<WasmYAML::StartSection>(Sec.get())) {
517 if (auto Err = writeSectionContent(StringStream, *S))
518 return Err;
519 } else if (auto S = dyn_cast<WasmYAML::ElemSection>(Sec.get())) {
520 if (auto Err = writeSectionContent(StringStream, *S))
521 return Err;
522 } else if (auto S = dyn_cast<WasmYAML::CodeSection>(Sec.get())) {
523 if (auto Err = writeSectionContent(StringStream, *S))
524 return Err;
525 } else if (auto S = dyn_cast<WasmYAML::DataSection>(Sec.get())) {
526 if (auto Err = writeSectionContent(StringStream, *S))
527 return Err;
528 } else {
529 errs() << "Unknown section type: " << Sec->Type << "\n";
530 return 1;
531 }
532 StringStream.flush();
533
534 // Write the section size followed by the content
535 encodeULEB128(OutString.size(), OS);
536 OS << OutString;
537 }
538
539 // write reloc sections for any section that have relocations
540 uint32_t SectionIndex = 0;
541 for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
542 if (Sec->Relocations.empty()) {
543 SectionIndex++;
544 continue;
545 }
546
547 writeUint8(OS, wasm::WASM_SEC_CUSTOM);
548 std::string OutString;
549 raw_string_ostream StringStream(OutString);
550 writeRelocSection(StringStream, *Sec, SectionIndex++);
551 StringStream.flush();
552
553 encodeULEB128(OutString.size(), OS);
554 OS << OutString;
555 }
556
557 return 0;
558 }
559
yaml2wasm(llvm::WasmYAML::Object & Doc,raw_ostream & Out)560 int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) {
561 WasmWriter Writer(Doc);
562
563 return Writer.writeWasm(Out);
564 }
565