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