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