blob: 792f7c108bc1ad51ac97933566f7b5259ae50cc8 [file] [log] [blame]
Derek Schuffd3d84fd2017-03-30 19:44:09 +00001//===- 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/// \brief The Wasm component of yaml2obj.
12///
13//===----------------------------------------------------------------------===//
14//
Derek Schuffd3d84fd2017-03-30 19:44:09 +000015#include "llvm/ObjectYAML/ObjectYAML.h"
16#include "llvm/Support/Endian.h"
17#include "llvm/Support/LEB128.h"
18
19using namespace llvm;
20
21/// This parses a yaml stream that represents a Wasm object file.
22/// See docs/yaml2obj for the yaml scheema.
23class WasmWriter {
24public:
25 WasmWriter(WasmYAML::Object &Obj) : Obj(Obj) {}
26 int writeWasm(raw_ostream &OS);
Sam Cleggb7787fd2017-06-20 04:04:59 +000027
28private:
Derek Schuffd3d84fd2017-03-30 19:44:09 +000029 int writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec);
Sam Clegg03cdd122017-05-05 18:12:34 +000030
Derek Schuffd3d84fd2017-03-30 19:44:09 +000031 int writeSectionContent(raw_ostream &OS, WasmYAML::CustomSection &Section);
32 int writeSectionContent(raw_ostream &OS, WasmYAML::TypeSection &Section);
33 int writeSectionContent(raw_ostream &OS, WasmYAML::ImportSection &Section);
34 int writeSectionContent(raw_ostream &OS, WasmYAML::FunctionSection &Section);
35 int writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section);
36 int writeSectionContent(raw_ostream &OS, WasmYAML::MemorySection &Section);
37 int writeSectionContent(raw_ostream &OS, WasmYAML::GlobalSection &Section);
38 int writeSectionContent(raw_ostream &OS, WasmYAML::ExportSection &Section);
39 int writeSectionContent(raw_ostream &OS, WasmYAML::StartSection &Section);
40 int writeSectionContent(raw_ostream &OS, WasmYAML::ElemSection &Section);
41 int writeSectionContent(raw_ostream &OS, WasmYAML::CodeSection &Section);
42 int writeSectionContent(raw_ostream &OS, WasmYAML::DataSection &Section);
43
Sam Cleggb7787fd2017-06-20 04:04:59 +000044 // Custom section types
45 int writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section);
46 int writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section);
Derek Schuffd3d84fd2017-03-30 19:44:09 +000047 WasmYAML::Object &Obj;
48};
49
50static int writeUint64(raw_ostream &OS, uint64_t Value) {
51 char Data[sizeof(Value)];
52 support::endian::write64le(Data, Value);
53 OS.write(Data, sizeof(Data));
54 return 0;
55}
56
57static int writeUint32(raw_ostream &OS, uint32_t Value) {
58 char Data[sizeof(Value)];
59 support::endian::write32le(Data, Value);
60 OS.write(Data, sizeof(Data));
61 return 0;
62}
63
64static int writeUint8(raw_ostream &OS, uint8_t Value) {
65 char Data[sizeof(Value)];
66 memcpy(Data, &Value, sizeof(Data));
67 OS.write(Data, sizeof(Data));
68 return 0;
69}
70
Sam Clegg03cdd122017-05-05 18:12:34 +000071static int writeStringRef(const StringRef &Str, raw_ostream &OS) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +000072 encodeULEB128(Str.size(), OS);
73 OS << Str;
74 return 0;
75}
76
Sam Clegg03cdd122017-05-05 18:12:34 +000077static int writeLimits(const WasmYAML::Limits &Lim, raw_ostream &OS) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +000078 encodeULEB128(Lim.Flags, OS);
79 encodeULEB128(Lim.Initial, OS);
80 if (Lim.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
81 encodeULEB128(Lim.Maximum, OS);
82 return 0;
83}
84
Sam Clegg03cdd122017-05-05 18:12:34 +000085static int writeInitExpr(const wasm::WasmInitExpr &InitExpr, raw_ostream &OS) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +000086 writeUint8(OS, InitExpr.Opcode);
87 switch (InitExpr.Opcode) {
88 case wasm::WASM_OPCODE_I32_CONST:
89 encodeSLEB128(InitExpr.Value.Int32, OS);
90 break;
91 case wasm::WASM_OPCODE_I64_CONST:
92 encodeSLEB128(InitExpr.Value.Int64, OS);
93 break;
94 case wasm::WASM_OPCODE_F32_CONST:
95 writeUint32(OS, InitExpr.Value.Float32);
96 break;
97 case wasm::WASM_OPCODE_F64_CONST:
98 writeUint64(OS, InitExpr.Value.Float64);
99 break;
100 case wasm::WASM_OPCODE_GET_GLOBAL:
101 encodeULEB128(InitExpr.Value.Global, OS);
102 break;
103 default:
104 errs() << "Unknown opcode in init_expr: " << InitExpr.Opcode;
105 return 1;
106 }
107 writeUint8(OS, wasm::WASM_OPCODE_END);
108 return 0;
109}
110
Sam Clegg9e1ade92017-06-27 20:27:59 +0000111class SubSectionWriter {
112 raw_ostream &OS;
113 std::string OutString;
114 raw_string_ostream StringStream;
Sam Cleggb7787fd2017-06-20 04:04:59 +0000115
Sam Clegg9e1ade92017-06-27 20:27:59 +0000116public:
117 SubSectionWriter(raw_ostream &OS) : OS(OS), StringStream(OutString) {}
Sam Cleggb7787fd2017-06-20 04:04:59 +0000118
Sam Clegg9e1ade92017-06-27 20:27:59 +0000119 void Done() {
Sam Cleggb7787fd2017-06-20 04:04:59 +0000120 StringStream.flush();
121 encodeULEB128(OutString.size(), OS);
122 OS << OutString;
Sam Clegg9e1ade92017-06-27 20:27:59 +0000123 OutString.clear();
124 }
125
126 raw_ostream& GetStream() {
127 return StringStream;
128 }
129};
130
131int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &Section) {
132 writeStringRef(Section.Name, OS);
133
134 SubSectionWriter SubSection(OS);
135
136 // DATA_SIZE subsection
137 encodeULEB128(wasm::WASM_DATA_SIZE, OS);
138 encodeULEB128(Section.DataSize, SubSection.GetStream());
139 SubSection.Done();
140
Sam Clegg9e1ade92017-06-27 20:27:59 +0000141 // SYMBOL_INFO subsection
142 if (Section.SymbolInfos.size()) {
143 encodeULEB128(wasm::WASM_SYMBOL_INFO, OS);
144
145 encodeULEB128(Section.SymbolInfos.size(), SubSection.GetStream());
146 for (const WasmYAML::SymbolInfo &Info : Section.SymbolInfos) {
147 writeStringRef(Info.Name, SubSection.GetStream());
148 encodeULEB128(Info.Flags, SubSection.GetStream());
149 }
150
151 SubSection.Done();
Sam Cleggb7787fd2017-06-20 04:04:59 +0000152 }
Sam Cleggd95ed952017-09-20 19:03:35 +0000153
154 // SEGMENT_NAMES subsection
Sam Clegg63ebb812017-09-29 16:50:08 +0000155 if (Section.SegmentInfos.size()) {
156 encodeULEB128(wasm::WASM_SEGMENT_INFO, OS);
157 encodeULEB128(Section.SegmentInfos.size(), SubSection.GetStream());
158 for (const WasmYAML::SegmentInfo &SegmentInfo : Section.SegmentInfos) {
Sam Clegg63ebb812017-09-29 16:50:08 +0000159 writeStringRef(SegmentInfo.Name, SubSection.GetStream());
160 encodeULEB128(SegmentInfo.Alignment, SubSection.GetStream());
161 encodeULEB128(SegmentInfo.Flags, SubSection.GetStream());
Sam Cleggd95ed952017-09-20 19:03:35 +0000162 }
163 SubSection.Done();
164 }
Sam Clegg42739982017-12-14 21:10:03 +0000165
166 // INIT_FUNCS subsection
167 if (Section.InitFunctions.size()) {
168 encodeULEB128(wasm::WASM_INIT_FUNCS, OS);
169 encodeULEB128(Section.InitFunctions.size(), SubSection.GetStream());
170 for (const WasmYAML::InitFunction &Func : Section.InitFunctions) {
171 encodeULEB128(Func.Priority, SubSection.GetStream());
172 encodeULEB128(Func.FunctionIndex, SubSection.GetStream());
173 }
174 SubSection.Done();
175 }
Sam Cleggb7787fd2017-06-20 04:04:59 +0000176 return 0;
177}
178
179int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section) {
Sam Clegg03cdd122017-05-05 18:12:34 +0000180 writeStringRef(Section.Name, OS);
181 if (Section.FunctionNames.size()) {
182 encodeULEB128(wasm::WASM_NAMES_FUNCTION, OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000183
Sam Clegg9e1ade92017-06-27 20:27:59 +0000184 SubSectionWriter SubSection(OS);
185
186 encodeULEB128(Section.FunctionNames.size(), SubSection.GetStream());
Sam Clegg03cdd122017-05-05 18:12:34 +0000187 for (const WasmYAML::NameEntry &NameEntry : Section.FunctionNames) {
Sam Clegg9e1ade92017-06-27 20:27:59 +0000188 encodeULEB128(NameEntry.Index, SubSection.GetStream());
189 writeStringRef(NameEntry.Name, SubSection.GetStream());
Sam Clegg03cdd122017-05-05 18:12:34 +0000190 }
191
Sam Clegg9e1ade92017-06-27 20:27:59 +0000192 SubSection.Done();
Sam Clegg03cdd122017-05-05 18:12:34 +0000193 }
194 return 0;
195}
196
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000197int WasmWriter::writeSectionContent(raw_ostream &OS,
198 WasmYAML::CustomSection &Section) {
Sam Cleggb7787fd2017-06-20 04:04:59 +0000199 if (auto S = dyn_cast<WasmYAML::NameSection>(&Section)) {
200 if (auto Err = writeSectionContent(OS, *S))
201 return Err;
202 } else if (auto S = dyn_cast<WasmYAML::LinkingSection>(&Section)) {
203 if (auto Err = writeSectionContent(OS, *S))
204 return Err;
Sam Clegg03cdd122017-05-05 18:12:34 +0000205 } else {
206 Section.Payload.writeAsBinary(OS);
207 }
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000208 return 0;
209}
210
211int WasmWriter::writeSectionContent(raw_ostream &OS,
212 WasmYAML::TypeSection &Section) {
213 encodeULEB128(Section.Signatures.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000214 for (const WasmYAML::Signature &Sig : Section.Signatures) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000215 encodeSLEB128(Sig.Form, OS);
216 encodeULEB128(Sig.ParamTypes.size(), OS);
217 for (auto ParamType : Sig.ParamTypes)
218 encodeSLEB128(ParamType, OS);
219 if (Sig.ReturnType == wasm::WASM_TYPE_NORESULT) {
220 encodeSLEB128(0, OS);
221 } else {
222 encodeULEB128(1, OS);
223 encodeSLEB128(Sig.ReturnType, OS);
224 }
225 }
226 return 0;
227}
228
229int WasmWriter::writeSectionContent(raw_ostream &OS,
230 WasmYAML::ImportSection &Section) {
231 encodeULEB128(Section.Imports.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000232 for (const WasmYAML::Import &Import : Section.Imports) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000233 writeStringRef(Import.Module, OS);
234 writeStringRef(Import.Field, OS);
235 encodeULEB128(Import.Kind, OS);
236 switch (Import.Kind) {
237 case wasm::WASM_EXTERNAL_FUNCTION:
238 encodeULEB128(Import.SigIndex, OS);
239 break;
240 case wasm::WASM_EXTERNAL_GLOBAL:
Sam Clegg41db5192017-05-10 00:14:04 +0000241 encodeSLEB128(Import.GlobalImport.Type, OS);
242 writeUint8(OS, Import.GlobalImport.Mutable);
Sam Clegg2ffff5a2017-05-09 23:48:41 +0000243 break;
244 case wasm::WASM_EXTERNAL_MEMORY:
245 writeLimits(Import.Memory, OS);
246 break;
247 case wasm::WASM_EXTERNAL_TABLE:
Sam Clegg41db5192017-05-10 00:14:04 +0000248 encodeSLEB128(Import.TableImport.ElemType, OS);
249 writeLimits(Import.TableImport.TableLimits, OS);
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000250 break;
251 default:
252 errs() << "Unknown import type: " << Import.Kind;
253 return 1;
254 }
255 }
256 return 0;
257}
258
259int WasmWriter::writeSectionContent(raw_ostream &OS,
260 WasmYAML::FunctionSection &Section) {
261 encodeULEB128(Section.FunctionTypes.size(), OS);
262 for (uint32_t FuncType : Section.FunctionTypes) {
263 encodeULEB128(FuncType, OS);
264 }
265 return 0;
266}
267
268int WasmWriter::writeSectionContent(raw_ostream &OS,
269 WasmYAML::ExportSection &Section) {
270 encodeULEB128(Section.Exports.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000271 for (const WasmYAML::Export &Export : Section.Exports) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000272 writeStringRef(Export.Name, OS);
273 encodeULEB128(Export.Kind, OS);
274 encodeULEB128(Export.Index, OS);
275 }
276 return 0;
277}
278
279int WasmWriter::writeSectionContent(raw_ostream &OS,
280 WasmYAML::StartSection &Section) {
281 encodeULEB128(Section.StartFunction, OS);
282 return 0;
283}
284
285int WasmWriter::writeSectionContent(raw_ostream &OS,
286 WasmYAML::TableSection &Section) {
287 encodeULEB128(Section.Tables.size(), OS);
288 for (auto &Table : Section.Tables) {
289 encodeSLEB128(Table.ElemType, OS);
290 writeLimits(Table.TableLimits, OS);
291 }
292 return 0;
293}
294
295int WasmWriter::writeSectionContent(raw_ostream &OS,
296 WasmYAML::MemorySection &Section) {
297 encodeULEB128(Section.Memories.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000298 for (const WasmYAML::Limits &Mem : Section.Memories) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000299 writeLimits(Mem, OS);
300 }
301 return 0;
302}
303
304int WasmWriter::writeSectionContent(raw_ostream &OS,
305 WasmYAML::GlobalSection &Section) {
306 encodeULEB128(Section.Globals.size(), OS);
307 for (auto &Global : Section.Globals) {
308 encodeSLEB128(Global.Type, OS);
309 writeUint8(OS, Global.Mutable);
310 writeInitExpr(Global.InitExpr, OS);
311 }
312 return 0;
313}
314
315int WasmWriter::writeSectionContent(raw_ostream &OS,
316 WasmYAML::ElemSection &Section) {
317 encodeULEB128(Section.Segments.size(), OS);
318 for (auto &Segment : Section.Segments) {
319 encodeULEB128(Segment.TableIndex, OS);
320 writeInitExpr(Segment.Offset, OS);
321
322 encodeULEB128(Segment.Functions.size(), OS);
323 for (auto &Function : Segment.Functions) {
324 encodeULEB128(Function, OS);
325 }
326 }
327 return 0;
328}
329
330int WasmWriter::writeSectionContent(raw_ostream &OS,
331 WasmYAML::CodeSection &Section) {
332 encodeULEB128(Section.Functions.size(), OS);
333 for (auto &Func : Section.Functions) {
334 std::string OutString;
335 raw_string_ostream StringStream(OutString);
336
337 encodeULEB128(Func.Locals.size(), StringStream);
338 for (auto &LocalDecl : Func.Locals) {
339 encodeULEB128(LocalDecl.Count, StringStream);
340 encodeSLEB128(LocalDecl.Type, StringStream);
341 }
342
343 Func.Body.writeAsBinary(StringStream);
344
345 // Write the section size followed by the content
346 StringStream.flush();
347 encodeULEB128(OutString.size(), OS);
348 OS << OutString;
349 }
350 return 0;
351}
352
353int WasmWriter::writeSectionContent(raw_ostream &OS,
354 WasmYAML::DataSection &Section) {
355 encodeULEB128(Section.Segments.size(), OS);
356 for (auto &Segment : Section.Segments) {
Sam Clegg9c07f942017-07-12 00:24:54 +0000357 encodeULEB128(Segment.MemoryIndex, OS);
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000358 writeInitExpr(Segment.Offset, OS);
359 encodeULEB128(Segment.Content.binary_size(), OS);
360 Segment.Content.writeAsBinary(OS);
361 }
362 return 0;
363}
364
365int WasmWriter::writeRelocSection(raw_ostream &OS,
366 WasmYAML::Section &Sec) {
367 StringRef Name;
368 switch (Sec.Type) {
369 case wasm::WASM_SEC_CODE:
370 Name = "reloc.CODE";
371 break;
372 case wasm::WASM_SEC_DATA:
373 Name = "reloc.DATA";
374 break;
375 default:
376 llvm_unreachable("not yet implemented");
377 return 1;
378 }
379
380 writeStringRef(Name, OS);
381 encodeULEB128(Sec.Type, OS);
382 encodeULEB128(Sec.Relocations.size(), OS);
383
384 for (auto Reloc: Sec.Relocations) {
385 encodeULEB128(Reloc.Type, OS);
386 encodeULEB128(Reloc.Offset, OS);
387 encodeULEB128(Reloc.Index, OS);
388 switch (Reloc.Type) {
Sam Clegg13a2e892017-09-01 17:32:01 +0000389 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
390 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
391 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000392 encodeULEB128(Reloc.Addend, OS);
393 }
394 }
395 return 0;
396}
397
398
399int WasmWriter::writeWasm(raw_ostream &OS) {
400 // Write headers
401 OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
402 writeUint32(OS, Obj.Header.Version);
403
404 // Write each section
405 for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
406 encodeULEB128(Sec->Type, OS);
407
408 std::string OutString;
409 raw_string_ostream StringStream(OutString);
410 if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get())) {
411 if (auto Err = writeSectionContent(StringStream, *S))
412 return Err;
413 } else if (auto S = dyn_cast<WasmYAML::TypeSection>(Sec.get())) {
414 if (auto Err = writeSectionContent(StringStream, *S))
415 return Err;
416 } else if (auto S = dyn_cast<WasmYAML::ImportSection>(Sec.get())) {
417 if (auto Err = writeSectionContent(StringStream, *S))
418 return Err;
419 } else if (auto S = dyn_cast<WasmYAML::FunctionSection>(Sec.get())) {
420 if (auto Err = writeSectionContent(StringStream, *S))
421 return Err;
422 } else if (auto S = dyn_cast<WasmYAML::TableSection>(Sec.get())) {
423 if (auto Err = writeSectionContent(StringStream, *S))
424 return Err;
425 } else if (auto S = dyn_cast<WasmYAML::MemorySection>(Sec.get())) {
426 if (auto Err = writeSectionContent(StringStream, *S))
427 return Err;
428 } else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) {
429 if (auto Err = writeSectionContent(StringStream, *S))
430 return Err;
431 } else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) {
432 if (auto Err = writeSectionContent(StringStream, *S))
433 return Err;
434 } else if (auto S = dyn_cast<WasmYAML::StartSection>(Sec.get())) {
435 if (auto Err = writeSectionContent(StringStream, *S))
436 return Err;
437 } else if (auto S = dyn_cast<WasmYAML::ElemSection>(Sec.get())) {
438 if (auto Err = writeSectionContent(StringStream, *S))
439 return Err;
440 } else if (auto S = dyn_cast<WasmYAML::CodeSection>(Sec.get())) {
441 if (auto Err = writeSectionContent(StringStream, *S))
442 return Err;
443 } else if (auto S = dyn_cast<WasmYAML::DataSection>(Sec.get())) {
444 if (auto Err = writeSectionContent(StringStream, *S))
445 return Err;
446 } else {
447 errs() << "Unknown section type: " << Sec->Type << "\n";
448 return 1;
449 }
450 StringStream.flush();
451
452 // Write the section size followed by the content
453 encodeULEB128(OutString.size(), OS);
454 OS << OutString;
455 }
456
457 // write reloc sections for any section that have relocations
458 for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
459 if (Sec->Relocations.empty())
460 continue;
461
462 encodeULEB128(wasm::WASM_SEC_CUSTOM, OS);
463 std::string OutString;
464 raw_string_ostream StringStream(OutString);
465 writeRelocSection(StringStream, *Sec);
466 StringStream.flush();
467
468 encodeULEB128(OutString.size(), OS);
469 OS << OutString;
470 }
471
472 return 0;
473}
474
475int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) {
476 WasmWriter Writer(Doc);
477
478 return Writer.writeWasm(Out);
479}