OSDN Git Service

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