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