xref: /freebsd/contrib/llvm-project/llvm/lib/ObjectYAML/WasmEmitter.cpp (revision c66ec88fed842fbaad62c30d510644ceb7bd2d71)
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::EventSection &Section);
45   void writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &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     encodeULEB128(Sig.ReturnTypes.size(), OS);
338     for (auto ReturnType : Sig.ReturnTypes)
339       writeUint8(OS, ReturnType);
340   }
341 }
342 
343 void WasmWriter::writeSectionContent(raw_ostream &OS,
344                                     WasmYAML::ImportSection &Section) {
345   encodeULEB128(Section.Imports.size(), OS);
346   for (const WasmYAML::Import &Import : Section.Imports) {
347     writeStringRef(Import.Module, OS);
348     writeStringRef(Import.Field, OS);
349     writeUint8(OS, Import.Kind);
350     switch (Import.Kind) {
351     case wasm::WASM_EXTERNAL_FUNCTION:
352       encodeULEB128(Import.SigIndex, OS);
353       NumImportedFunctions++;
354       break;
355     case wasm::WASM_EXTERNAL_GLOBAL:
356       writeUint8(OS, Import.GlobalImport.Type);
357       writeUint8(OS, Import.GlobalImport.Mutable);
358       NumImportedGlobals++;
359       break;
360     case wasm::WASM_EXTERNAL_EVENT:
361       writeUint32(OS, Import.EventImport.Attribute);
362       writeUint32(OS, Import.EventImport.SigIndex);
363       NumImportedGlobals++;
364       break;
365     case wasm::WASM_EXTERNAL_MEMORY:
366       writeLimits(Import.Memory, OS);
367       break;
368     case wasm::WASM_EXTERNAL_TABLE:
369       writeUint8(OS, Import.TableImport.ElemType);
370       writeLimits(Import.TableImport.TableLimits, OS);
371       break;
372     default:
373       reportError("unknown import type: " +Twine(Import.Kind));
374       return;
375     }
376   }
377 }
378 
379 void WasmWriter::writeSectionContent(raw_ostream &OS,
380                                      WasmYAML::FunctionSection &Section) {
381   encodeULEB128(Section.FunctionTypes.size(), OS);
382   for (uint32_t FuncType : Section.FunctionTypes)
383     encodeULEB128(FuncType, OS);
384 }
385 
386 void WasmWriter::writeSectionContent(raw_ostream &OS,
387                                     WasmYAML::ExportSection &Section) {
388   encodeULEB128(Section.Exports.size(), OS);
389   for (const WasmYAML::Export &Export : Section.Exports) {
390     writeStringRef(Export.Name, OS);
391     writeUint8(OS, Export.Kind);
392     encodeULEB128(Export.Index, OS);
393   }
394 }
395 
396 void WasmWriter::writeSectionContent(raw_ostream &OS,
397                                      WasmYAML::StartSection &Section) {
398   encodeULEB128(Section.StartFunction, OS);
399 }
400 
401 void WasmWriter::writeSectionContent(raw_ostream &OS,
402                                      WasmYAML::TableSection &Section) {
403   encodeULEB128(Section.Tables.size(), OS);
404   for (auto &Table : Section.Tables) {
405     writeUint8(OS, Table.ElemType);
406     writeLimits(Table.TableLimits, OS);
407   }
408 }
409 
410 void WasmWriter::writeSectionContent(raw_ostream &OS,
411                                      WasmYAML::MemorySection &Section) {
412   encodeULEB128(Section.Memories.size(), OS);
413   for (const WasmYAML::Limits &Mem : Section.Memories)
414     writeLimits(Mem, OS);
415 }
416 
417 void WasmWriter::writeSectionContent(raw_ostream &OS,
418                                      WasmYAML::EventSection &Section) {
419   encodeULEB128(Section.Events.size(), OS);
420   uint32_t ExpectedIndex = NumImportedEvents;
421   for (auto &Event : Section.Events) {
422     if (Event.Index != ExpectedIndex) {
423       reportError("unexpected event index: " + Twine(Event.Index));
424       return;
425     }
426     ++ExpectedIndex;
427     encodeULEB128(Event.Attribute, OS);
428     encodeULEB128(Event.SigIndex, OS);
429   }
430 }
431 
432 void WasmWriter::writeSectionContent(raw_ostream &OS,
433                                      WasmYAML::GlobalSection &Section) {
434   encodeULEB128(Section.Globals.size(), OS);
435   uint32_t ExpectedIndex = NumImportedGlobals;
436   for (auto &Global : Section.Globals) {
437     if (Global.Index != ExpectedIndex) {
438       reportError("unexpected global index: " + Twine(Global.Index));
439       return;
440     }
441     ++ExpectedIndex;
442     writeUint8(OS, Global.Type);
443     writeUint8(OS, Global.Mutable);
444     writeInitExpr(OS, Global.InitExpr);
445   }
446 }
447 
448 void WasmWriter::writeSectionContent(raw_ostream &OS,
449                                      WasmYAML::ElemSection &Section) {
450   encodeULEB128(Section.Segments.size(), OS);
451   for (auto &Segment : Section.Segments) {
452     encodeULEB128(Segment.TableIndex, OS);
453     writeInitExpr(OS, Segment.Offset);
454 
455     encodeULEB128(Segment.Functions.size(), OS);
456     for (auto &Function : Segment.Functions)
457       encodeULEB128(Function, OS);
458   }
459 }
460 
461 void WasmWriter::writeSectionContent(raw_ostream &OS,
462                                     WasmYAML::CodeSection &Section) {
463   encodeULEB128(Section.Functions.size(), OS);
464   uint32_t ExpectedIndex = NumImportedFunctions;
465   for (auto &Func : Section.Functions) {
466     std::string OutString;
467     raw_string_ostream StringStream(OutString);
468     if (Func.Index != ExpectedIndex) {
469       reportError("unexpected function index: " + Twine(Func.Index));
470       return;
471     }
472     ++ExpectedIndex;
473 
474     encodeULEB128(Func.Locals.size(), StringStream);
475     for (auto &LocalDecl : Func.Locals) {
476       encodeULEB128(LocalDecl.Count, StringStream);
477       writeUint8(StringStream, LocalDecl.Type);
478     }
479 
480     Func.Body.writeAsBinary(StringStream);
481 
482     // Write the section size followed by the content
483     StringStream.flush();
484     encodeULEB128(OutString.size(), OS);
485     OS << OutString;
486   }
487 }
488 
489 void WasmWriter::writeSectionContent(raw_ostream &OS,
490                                      WasmYAML::DataSection &Section) {
491   encodeULEB128(Section.Segments.size(), OS);
492   for (auto &Segment : Section.Segments) {
493     encodeULEB128(Segment.InitFlags, OS);
494     if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
495       encodeULEB128(Segment.MemoryIndex, OS);
496     if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0)
497       writeInitExpr(OS, Segment.Offset);
498     encodeULEB128(Segment.Content.binary_size(), OS);
499     Segment.Content.writeAsBinary(OS);
500   }
501 }
502 
503 void WasmWriter::writeSectionContent(raw_ostream &OS,
504                                      WasmYAML::DataCountSection &Section) {
505   encodeULEB128(Section.Count, OS);
506 }
507 
508 void WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec,
509                                   uint32_t SectionIndex) {
510   switch (Sec.Type) {
511   case wasm::WASM_SEC_CODE:
512     writeStringRef("reloc.CODE", OS);
513     break;
514   case wasm::WASM_SEC_DATA:
515     writeStringRef("reloc.DATA", OS);
516     break;
517   case wasm::WASM_SEC_CUSTOM: {
518     auto *CustomSection = cast<WasmYAML::CustomSection>(&Sec);
519     writeStringRef(("reloc." + CustomSection->Name).str(), OS);
520     break;
521   }
522   default:
523     llvm_unreachable("not yet implemented");
524   }
525 
526   encodeULEB128(SectionIndex, OS);
527   encodeULEB128(Sec.Relocations.size(), OS);
528 
529   for (auto Reloc : Sec.Relocations) {
530     writeUint8(OS, Reloc.Type);
531     encodeULEB128(Reloc.Offset, OS);
532     encodeULEB128(Reloc.Index, OS);
533     switch (Reloc.Type) {
534     case wasm::R_WASM_MEMORY_ADDR_LEB:
535     case wasm::R_WASM_MEMORY_ADDR_LEB64:
536     case wasm::R_WASM_MEMORY_ADDR_SLEB:
537     case wasm::R_WASM_MEMORY_ADDR_SLEB64:
538     case wasm::R_WASM_MEMORY_ADDR_I32:
539     case wasm::R_WASM_MEMORY_ADDR_I64:
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::EventSection>(Sec.get()))
578       writeSectionContent(StringStream, *S);
579     else if (auto S = dyn_cast<WasmYAML::GlobalSection>(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