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