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