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