blob: 3eae8727b607e7bc9358154199d6910091c3ae38 [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 Cleggb7787fd2017-06-20 04:04:59 +0000165 return 0;
166}
167
168int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::NameSection &Section) {
Sam Clegg03cdd122017-05-05 18:12:34 +0000169 writeStringRef(Section.Name, OS);
170 if (Section.FunctionNames.size()) {
171 encodeULEB128(wasm::WASM_NAMES_FUNCTION, OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000172
Sam Clegg9e1ade92017-06-27 20:27:59 +0000173 SubSectionWriter SubSection(OS);
174
175 encodeULEB128(Section.FunctionNames.size(), SubSection.GetStream());
Sam Clegg03cdd122017-05-05 18:12:34 +0000176 for (const WasmYAML::NameEntry &NameEntry : Section.FunctionNames) {
Sam Clegg9e1ade92017-06-27 20:27:59 +0000177 encodeULEB128(NameEntry.Index, SubSection.GetStream());
178 writeStringRef(NameEntry.Name, SubSection.GetStream());
Sam Clegg03cdd122017-05-05 18:12:34 +0000179 }
180
Sam Clegg9e1ade92017-06-27 20:27:59 +0000181 SubSection.Done();
Sam Clegg03cdd122017-05-05 18:12:34 +0000182 }
183 return 0;
184}
185
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000186int WasmWriter::writeSectionContent(raw_ostream &OS,
187 WasmYAML::CustomSection &Section) {
Sam Cleggb7787fd2017-06-20 04:04:59 +0000188 if (auto S = dyn_cast<WasmYAML::NameSection>(&Section)) {
189 if (auto Err = writeSectionContent(OS, *S))
190 return Err;
191 } else if (auto S = dyn_cast<WasmYAML::LinkingSection>(&Section)) {
192 if (auto Err = writeSectionContent(OS, *S))
193 return Err;
Sam Clegg03cdd122017-05-05 18:12:34 +0000194 } else {
195 Section.Payload.writeAsBinary(OS);
196 }
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000197 return 0;
198}
199
200int WasmWriter::writeSectionContent(raw_ostream &OS,
201 WasmYAML::TypeSection &Section) {
202 encodeULEB128(Section.Signatures.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000203 for (const WasmYAML::Signature &Sig : Section.Signatures) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000204 encodeSLEB128(Sig.Form, OS);
205 encodeULEB128(Sig.ParamTypes.size(), OS);
206 for (auto ParamType : Sig.ParamTypes)
207 encodeSLEB128(ParamType, OS);
208 if (Sig.ReturnType == wasm::WASM_TYPE_NORESULT) {
209 encodeSLEB128(0, OS);
210 } else {
211 encodeULEB128(1, OS);
212 encodeSLEB128(Sig.ReturnType, OS);
213 }
214 }
215 return 0;
216}
217
218int WasmWriter::writeSectionContent(raw_ostream &OS,
219 WasmYAML::ImportSection &Section) {
220 encodeULEB128(Section.Imports.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000221 for (const WasmYAML::Import &Import : Section.Imports) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000222 writeStringRef(Import.Module, OS);
223 writeStringRef(Import.Field, OS);
224 encodeULEB128(Import.Kind, OS);
225 switch (Import.Kind) {
226 case wasm::WASM_EXTERNAL_FUNCTION:
227 encodeULEB128(Import.SigIndex, OS);
228 break;
229 case wasm::WASM_EXTERNAL_GLOBAL:
Sam Clegg41db5192017-05-10 00:14:04 +0000230 encodeSLEB128(Import.GlobalImport.Type, OS);
231 writeUint8(OS, Import.GlobalImport.Mutable);
Sam Clegg2ffff5a2017-05-09 23:48:41 +0000232 break;
233 case wasm::WASM_EXTERNAL_MEMORY:
234 writeLimits(Import.Memory, OS);
235 break;
236 case wasm::WASM_EXTERNAL_TABLE:
Sam Clegg41db5192017-05-10 00:14:04 +0000237 encodeSLEB128(Import.TableImport.ElemType, OS);
238 writeLimits(Import.TableImport.TableLimits, OS);
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000239 break;
240 default:
241 errs() << "Unknown import type: " << Import.Kind;
242 return 1;
243 }
244 }
245 return 0;
246}
247
248int WasmWriter::writeSectionContent(raw_ostream &OS,
249 WasmYAML::FunctionSection &Section) {
250 encodeULEB128(Section.FunctionTypes.size(), OS);
251 for (uint32_t FuncType : Section.FunctionTypes) {
252 encodeULEB128(FuncType, OS);
253 }
254 return 0;
255}
256
257int WasmWriter::writeSectionContent(raw_ostream &OS,
258 WasmYAML::ExportSection &Section) {
259 encodeULEB128(Section.Exports.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000260 for (const WasmYAML::Export &Export : Section.Exports) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000261 writeStringRef(Export.Name, OS);
262 encodeULEB128(Export.Kind, OS);
263 encodeULEB128(Export.Index, OS);
264 }
265 return 0;
266}
267
268int WasmWriter::writeSectionContent(raw_ostream &OS,
269 WasmYAML::StartSection &Section) {
270 encodeULEB128(Section.StartFunction, OS);
271 return 0;
272}
273
274int WasmWriter::writeSectionContent(raw_ostream &OS,
275 WasmYAML::TableSection &Section) {
276 encodeULEB128(Section.Tables.size(), OS);
277 for (auto &Table : Section.Tables) {
278 encodeSLEB128(Table.ElemType, OS);
279 writeLimits(Table.TableLimits, OS);
280 }
281 return 0;
282}
283
284int WasmWriter::writeSectionContent(raw_ostream &OS,
285 WasmYAML::MemorySection &Section) {
286 encodeULEB128(Section.Memories.size(), OS);
Sam Clegg03cdd122017-05-05 18:12:34 +0000287 for (const WasmYAML::Limits &Mem : Section.Memories) {
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000288 writeLimits(Mem, OS);
289 }
290 return 0;
291}
292
293int WasmWriter::writeSectionContent(raw_ostream &OS,
294 WasmYAML::GlobalSection &Section) {
295 encodeULEB128(Section.Globals.size(), OS);
296 for (auto &Global : Section.Globals) {
297 encodeSLEB128(Global.Type, OS);
298 writeUint8(OS, Global.Mutable);
299 writeInitExpr(Global.InitExpr, OS);
300 }
301 return 0;
302}
303
304int WasmWriter::writeSectionContent(raw_ostream &OS,
305 WasmYAML::ElemSection &Section) {
306 encodeULEB128(Section.Segments.size(), OS);
307 for (auto &Segment : Section.Segments) {
308 encodeULEB128(Segment.TableIndex, OS);
309 writeInitExpr(Segment.Offset, OS);
310
311 encodeULEB128(Segment.Functions.size(), OS);
312 for (auto &Function : Segment.Functions) {
313 encodeULEB128(Function, OS);
314 }
315 }
316 return 0;
317}
318
319int WasmWriter::writeSectionContent(raw_ostream &OS,
320 WasmYAML::CodeSection &Section) {
321 encodeULEB128(Section.Functions.size(), OS);
322 for (auto &Func : Section.Functions) {
323 std::string OutString;
324 raw_string_ostream StringStream(OutString);
325
326 encodeULEB128(Func.Locals.size(), StringStream);
327 for (auto &LocalDecl : Func.Locals) {
328 encodeULEB128(LocalDecl.Count, StringStream);
329 encodeSLEB128(LocalDecl.Type, StringStream);
330 }
331
332 Func.Body.writeAsBinary(StringStream);
333
334 // Write the section size followed by the content
335 StringStream.flush();
336 encodeULEB128(OutString.size(), OS);
337 OS << OutString;
338 }
339 return 0;
340}
341
342int WasmWriter::writeSectionContent(raw_ostream &OS,
343 WasmYAML::DataSection &Section) {
344 encodeULEB128(Section.Segments.size(), OS);
345 for (auto &Segment : Section.Segments) {
Sam Clegg9c07f942017-07-12 00:24:54 +0000346 encodeULEB128(Segment.MemoryIndex, OS);
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000347 writeInitExpr(Segment.Offset, OS);
348 encodeULEB128(Segment.Content.binary_size(), OS);
349 Segment.Content.writeAsBinary(OS);
350 }
351 return 0;
352}
353
354int WasmWriter::writeRelocSection(raw_ostream &OS,
355 WasmYAML::Section &Sec) {
356 StringRef Name;
357 switch (Sec.Type) {
358 case wasm::WASM_SEC_CODE:
359 Name = "reloc.CODE";
360 break;
361 case wasm::WASM_SEC_DATA:
362 Name = "reloc.DATA";
363 break;
364 default:
365 llvm_unreachable("not yet implemented");
366 return 1;
367 }
368
369 writeStringRef(Name, OS);
370 encodeULEB128(Sec.Type, OS);
371 encodeULEB128(Sec.Relocations.size(), OS);
372
373 for (auto Reloc: Sec.Relocations) {
374 encodeULEB128(Reloc.Type, OS);
375 encodeULEB128(Reloc.Offset, OS);
376 encodeULEB128(Reloc.Index, OS);
377 switch (Reloc.Type) {
Sam Clegg13a2e892017-09-01 17:32:01 +0000378 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
379 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
380 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
Derek Schuffd3d84fd2017-03-30 19:44:09 +0000381 encodeULEB128(Reloc.Addend, OS);
382 }
383 }
384 return 0;
385}
386
387
388int WasmWriter::writeWasm(raw_ostream &OS) {
389 // Write headers
390 OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
391 writeUint32(OS, Obj.Header.Version);
392
393 // Write each section
394 for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
395 encodeULEB128(Sec->Type, OS);
396
397 std::string OutString;
398 raw_string_ostream StringStream(OutString);
399 if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get())) {
400 if (auto Err = writeSectionContent(StringStream, *S))
401 return Err;
402 } else if (auto S = dyn_cast<WasmYAML::TypeSection>(Sec.get())) {
403 if (auto Err = writeSectionContent(StringStream, *S))
404 return Err;
405 } else if (auto S = dyn_cast<WasmYAML::ImportSection>(Sec.get())) {
406 if (auto Err = writeSectionContent(StringStream, *S))
407 return Err;
408 } else if (auto S = dyn_cast<WasmYAML::FunctionSection>(Sec.get())) {
409 if (auto Err = writeSectionContent(StringStream, *S))
410 return Err;
411 } else if (auto S = dyn_cast<WasmYAML::TableSection>(Sec.get())) {
412 if (auto Err = writeSectionContent(StringStream, *S))
413 return Err;
414 } else if (auto S = dyn_cast<WasmYAML::MemorySection>(Sec.get())) {
415 if (auto Err = writeSectionContent(StringStream, *S))
416 return Err;
417 } else if (auto S = dyn_cast<WasmYAML::GlobalSection>(Sec.get())) {
418 if (auto Err = writeSectionContent(StringStream, *S))
419 return Err;
420 } else if (auto S = dyn_cast<WasmYAML::ExportSection>(Sec.get())) {
421 if (auto Err = writeSectionContent(StringStream, *S))
422 return Err;
423 } else if (auto S = dyn_cast<WasmYAML::StartSection>(Sec.get())) {
424 if (auto Err = writeSectionContent(StringStream, *S))
425 return Err;
426 } else if (auto S = dyn_cast<WasmYAML::ElemSection>(Sec.get())) {
427 if (auto Err = writeSectionContent(StringStream, *S))
428 return Err;
429 } else if (auto S = dyn_cast<WasmYAML::CodeSection>(Sec.get())) {
430 if (auto Err = writeSectionContent(StringStream, *S))
431 return Err;
432 } else if (auto S = dyn_cast<WasmYAML::DataSection>(Sec.get())) {
433 if (auto Err = writeSectionContent(StringStream, *S))
434 return Err;
435 } else {
436 errs() << "Unknown section type: " << Sec->Type << "\n";
437 return 1;
438 }
439 StringStream.flush();
440
441 // Write the section size followed by the content
442 encodeULEB128(OutString.size(), OS);
443 OS << OutString;
444 }
445
446 // write reloc sections for any section that have relocations
447 for (const std::unique_ptr<WasmYAML::Section> &Sec : Obj.Sections) {
448 if (Sec->Relocations.empty())
449 continue;
450
451 encodeULEB128(wasm::WASM_SEC_CUSTOM, OS);
452 std::string OutString;
453 raw_string_ostream StringStream(OutString);
454 writeRelocSection(StringStream, *Sec);
455 StringStream.flush();
456
457 encodeULEB128(OutString.size(), OS);
458 OS << OutString;
459 }
460
461 return 0;
462}
463
464int yaml2wasm(llvm::WasmYAML::Object &Doc, raw_ostream &Out) {
465 WasmWriter Writer(Doc);
466
467 return Writer.writeWasm(Out);
468}