Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp
35232 views
1
//===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
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
#include "llvm/ADT/ArrayRef.h"
10
#include "llvm/ADT/DenseSet.h"
11
#include "llvm/ADT/SmallSet.h"
12
#include "llvm/ADT/StringRef.h"
13
#include "llvm/ADT/StringSet.h"
14
#include "llvm/ADT/StringSwitch.h"
15
#include "llvm/BinaryFormat/Wasm.h"
16
#include "llvm/Object/Binary.h"
17
#include "llvm/Object/Error.h"
18
#include "llvm/Object/ObjectFile.h"
19
#include "llvm/Object/SymbolicFile.h"
20
#include "llvm/Object/Wasm.h"
21
#include "llvm/Support/Endian.h"
22
#include "llvm/Support/Error.h"
23
#include "llvm/Support/ErrorHandling.h"
24
#include "llvm/Support/Format.h"
25
#include "llvm/Support/LEB128.h"
26
#include "llvm/Support/ScopedPrinter.h"
27
#include "llvm/TargetParser/SubtargetFeature.h"
28
#include "llvm/TargetParser/Triple.h"
29
#include <algorithm>
30
#include <cassert>
31
#include <cstdint>
32
#include <cstring>
33
#include <limits>
34
35
#define DEBUG_TYPE "wasm-object"
36
37
using namespace llvm;
38
using namespace object;
39
40
void WasmSymbol::print(raw_ostream &Out) const {
41
Out << "Name=" << Info.Name
42
<< ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
43
<< Twine::utohexstr(Info.Flags) << " [";
44
switch (getBinding()) {
45
case wasm::WASM_SYMBOL_BINDING_GLOBAL: Out << "global"; break;
46
case wasm::WASM_SYMBOL_BINDING_LOCAL: Out << "local"; break;
47
case wasm::WASM_SYMBOL_BINDING_WEAK: Out << "weak"; break;
48
}
49
if (isHidden()) {
50
Out << ", hidden";
51
} else {
52
Out << ", default";
53
}
54
Out << "]";
55
if (!isTypeData()) {
56
Out << ", ElemIndex=" << Info.ElementIndex;
57
} else if (isDefined()) {
58
Out << ", Segment=" << Info.DataRef.Segment;
59
Out << ", Offset=" << Info.DataRef.Offset;
60
Out << ", Size=" << Info.DataRef.Size;
61
}
62
}
63
64
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
65
LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
66
#endif
67
68
Expected<std::unique_ptr<WasmObjectFile>>
69
ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
70
Error Err = Error::success();
71
auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
72
if (Err)
73
return std::move(Err);
74
75
return std::move(ObjectFile);
76
}
77
78
#define VARINT7_MAX ((1 << 7) - 1)
79
#define VARINT7_MIN (-(1 << 7))
80
#define VARUINT7_MAX (1 << 7)
81
#define VARUINT1_MAX (1)
82
83
static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
84
if (Ctx.Ptr == Ctx.End)
85
report_fatal_error("EOF while reading uint8");
86
return *Ctx.Ptr++;
87
}
88
89
static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
90
if (Ctx.Ptr + 4 > Ctx.End)
91
report_fatal_error("EOF while reading uint32");
92
uint32_t Result = support::endian::read32le(Ctx.Ptr);
93
Ctx.Ptr += 4;
94
return Result;
95
}
96
97
static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
98
if (Ctx.Ptr + 4 > Ctx.End)
99
report_fatal_error("EOF while reading float64");
100
int32_t Result = 0;
101
memcpy(&Result, Ctx.Ptr, sizeof(Result));
102
Ctx.Ptr += sizeof(Result);
103
return Result;
104
}
105
106
static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
107
if (Ctx.Ptr + 8 > Ctx.End)
108
report_fatal_error("EOF while reading float64");
109
int64_t Result = 0;
110
memcpy(&Result, Ctx.Ptr, sizeof(Result));
111
Ctx.Ptr += sizeof(Result);
112
return Result;
113
}
114
115
static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
116
unsigned Count;
117
const char *Error = nullptr;
118
uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
119
if (Error)
120
report_fatal_error(Error);
121
Ctx.Ptr += Count;
122
return Result;
123
}
124
125
static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
126
uint32_t StringLen = readULEB128(Ctx);
127
if (Ctx.Ptr + StringLen > Ctx.End)
128
report_fatal_error("EOF while reading string");
129
StringRef Return =
130
StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
131
Ctx.Ptr += StringLen;
132
return Return;
133
}
134
135
static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
136
unsigned Count;
137
const char *Error = nullptr;
138
uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
139
if (Error)
140
report_fatal_error(Error);
141
Ctx.Ptr += Count;
142
return Result;
143
}
144
145
static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
146
int64_t Result = readLEB128(Ctx);
147
if (Result > VARUINT1_MAX || Result < 0)
148
report_fatal_error("LEB is outside Varuint1 range");
149
return Result;
150
}
151
152
static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
153
int64_t Result = readLEB128(Ctx);
154
if (Result > INT32_MAX || Result < INT32_MIN)
155
report_fatal_error("LEB is outside Varint32 range");
156
return Result;
157
}
158
159
static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
160
uint64_t Result = readULEB128(Ctx);
161
if (Result > UINT32_MAX)
162
report_fatal_error("LEB is outside Varuint32 range");
163
return Result;
164
}
165
166
static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
167
return readLEB128(Ctx);
168
}
169
170
static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
171
return readULEB128(Ctx);
172
}
173
174
static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
175
return readUint8(Ctx);
176
}
177
178
static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx,
179
uint32_t Code) {
180
// only directly encoded FUNCREF/EXTERNREF/EXNREF are supported
181
// (not ref null func, ref null extern, or ref null exn)
182
switch (Code) {
183
case wasm::WASM_TYPE_I32:
184
case wasm::WASM_TYPE_I64:
185
case wasm::WASM_TYPE_F32:
186
case wasm::WASM_TYPE_F64:
187
case wasm::WASM_TYPE_V128:
188
case wasm::WASM_TYPE_FUNCREF:
189
case wasm::WASM_TYPE_EXTERNREF:
190
case wasm::WASM_TYPE_EXNREF:
191
return wasm::ValType(Code);
192
}
193
if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
194
/* Discard HeapType */ readVarint64(Ctx);
195
}
196
return wasm::ValType(wasm::ValType::OTHERREF);
197
}
198
199
static Error readInitExpr(wasm::WasmInitExpr &Expr,
200
WasmObjectFile::ReadContext &Ctx) {
201
auto Start = Ctx.Ptr;
202
203
Expr.Extended = false;
204
Expr.Inst.Opcode = readOpcode(Ctx);
205
switch (Expr.Inst.Opcode) {
206
case wasm::WASM_OPCODE_I32_CONST:
207
Expr.Inst.Value.Int32 = readVarint32(Ctx);
208
break;
209
case wasm::WASM_OPCODE_I64_CONST:
210
Expr.Inst.Value.Int64 = readVarint64(Ctx);
211
break;
212
case wasm::WASM_OPCODE_F32_CONST:
213
Expr.Inst.Value.Float32 = readFloat32(Ctx);
214
break;
215
case wasm::WASM_OPCODE_F64_CONST:
216
Expr.Inst.Value.Float64 = readFloat64(Ctx);
217
break;
218
case wasm::WASM_OPCODE_GLOBAL_GET:
219
Expr.Inst.Value.Global = readULEB128(Ctx);
220
break;
221
case wasm::WASM_OPCODE_REF_NULL: {
222
/* Discard type */ parseValType(Ctx, readVaruint32(Ctx));
223
break;
224
}
225
default:
226
Expr.Extended = true;
227
}
228
229
if (!Expr.Extended) {
230
uint8_t EndOpcode = readOpcode(Ctx);
231
if (EndOpcode != wasm::WASM_OPCODE_END)
232
Expr.Extended = true;
233
}
234
235
if (Expr.Extended) {
236
Ctx.Ptr = Start;
237
while (true) {
238
uint8_t Opcode = readOpcode(Ctx);
239
switch (Opcode) {
240
case wasm::WASM_OPCODE_I32_CONST:
241
case wasm::WASM_OPCODE_GLOBAL_GET:
242
case wasm::WASM_OPCODE_REF_NULL:
243
case wasm::WASM_OPCODE_REF_FUNC:
244
case wasm::WASM_OPCODE_I64_CONST:
245
readULEB128(Ctx);
246
break;
247
case wasm::WASM_OPCODE_F32_CONST:
248
readFloat32(Ctx);
249
break;
250
case wasm::WASM_OPCODE_F64_CONST:
251
readFloat64(Ctx);
252
break;
253
case wasm::WASM_OPCODE_I32_ADD:
254
case wasm::WASM_OPCODE_I32_SUB:
255
case wasm::WASM_OPCODE_I32_MUL:
256
case wasm::WASM_OPCODE_I64_ADD:
257
case wasm::WASM_OPCODE_I64_SUB:
258
case wasm::WASM_OPCODE_I64_MUL:
259
break;
260
case wasm::WASM_OPCODE_GC_PREFIX:
261
break;
262
// The GC opcodes are in a separate (prefixed space). This flat switch
263
// structure works as long as there is no overlap between the GC and
264
// general opcodes used in init exprs.
265
case wasm::WASM_OPCODE_STRUCT_NEW:
266
case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT:
267
case wasm::WASM_OPCODE_ARRAY_NEW:
268
case wasm::WASM_OPCODE_ARRAY_NEW_DEFAULT:
269
readULEB128(Ctx); // heap type index
270
break;
271
case wasm::WASM_OPCODE_ARRAY_NEW_FIXED:
272
readULEB128(Ctx); // heap type index
273
readULEB128(Ctx); // array size
274
break;
275
case wasm::WASM_OPCODE_REF_I31:
276
break;
277
case wasm::WASM_OPCODE_END:
278
Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
279
return Error::success();
280
default:
281
return make_error<GenericBinaryError>(
282
Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)),
283
object_error::parse_failed);
284
}
285
}
286
}
287
288
return Error::success();
289
}
290
291
static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
292
wasm::WasmLimits Result;
293
Result.Flags = readVaruint32(Ctx);
294
Result.Minimum = readVaruint64(Ctx);
295
if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
296
Result.Maximum = readVaruint64(Ctx);
297
return Result;
298
}
299
300
static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
301
wasm::WasmTableType TableType;
302
auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
303
TableType.ElemType = ElemType;
304
TableType.Limits = readLimits(Ctx);
305
return TableType;
306
}
307
308
static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
309
WasmSectionOrderChecker &Checker) {
310
Section.Type = readUint8(Ctx);
311
LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
312
// When reading the section's size, store the size of the LEB used to encode
313
// it. This allows objcopy/strip to reproduce the binary identically.
314
const uint8_t *PreSizePtr = Ctx.Ptr;
315
uint32_t Size = readVaruint32(Ctx);
316
Section.HeaderSecSizeEncodingLen = Ctx.Ptr - PreSizePtr;
317
Section.Offset = Ctx.Ptr - Ctx.Start;
318
if (Size == 0)
319
return make_error<StringError>("zero length section",
320
object_error::parse_failed);
321
if (Ctx.Ptr + Size > Ctx.End)
322
return make_error<StringError>("section too large",
323
object_error::parse_failed);
324
if (Section.Type == wasm::WASM_SEC_CUSTOM) {
325
WasmObjectFile::ReadContext SectionCtx;
326
SectionCtx.Start = Ctx.Ptr;
327
SectionCtx.Ptr = Ctx.Ptr;
328
SectionCtx.End = Ctx.Ptr + Size;
329
330
Section.Name = readString(SectionCtx);
331
332
uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
333
Ctx.Ptr += SectionNameSize;
334
Size -= SectionNameSize;
335
}
336
337
if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
338
return make_error<StringError>("out of order section type: " +
339
llvm::to_string(Section.Type),
340
object_error::parse_failed);
341
}
342
343
Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
344
Ctx.Ptr += Size;
345
return Error::success();
346
}
347
348
WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
349
: ObjectFile(Binary::ID_Wasm, Buffer) {
350
ErrorAsOutParameter ErrAsOutParam(&Err);
351
Header.Magic = getData().substr(0, 4);
352
if (Header.Magic != StringRef("\0asm", 4)) {
353
Err = make_error<StringError>("invalid magic number",
354
object_error::parse_failed);
355
return;
356
}
357
358
ReadContext Ctx;
359
Ctx.Start = getData().bytes_begin();
360
Ctx.Ptr = Ctx.Start + 4;
361
Ctx.End = Ctx.Start + getData().size();
362
363
if (Ctx.Ptr + 4 > Ctx.End) {
364
Err = make_error<StringError>("missing version number",
365
object_error::parse_failed);
366
return;
367
}
368
369
Header.Version = readUint32(Ctx);
370
if (Header.Version != wasm::WasmVersion) {
371
Err = make_error<StringError>("invalid version number: " +
372
Twine(Header.Version),
373
object_error::parse_failed);
374
return;
375
}
376
377
WasmSectionOrderChecker Checker;
378
while (Ctx.Ptr < Ctx.End) {
379
WasmSection Sec;
380
if ((Err = readSection(Sec, Ctx, Checker)))
381
return;
382
if ((Err = parseSection(Sec)))
383
return;
384
385
Sections.push_back(Sec);
386
}
387
}
388
389
Error WasmObjectFile::parseSection(WasmSection &Sec) {
390
ReadContext Ctx;
391
Ctx.Start = Sec.Content.data();
392
Ctx.End = Ctx.Start + Sec.Content.size();
393
Ctx.Ptr = Ctx.Start;
394
switch (Sec.Type) {
395
case wasm::WASM_SEC_CUSTOM:
396
return parseCustomSection(Sec, Ctx);
397
case wasm::WASM_SEC_TYPE:
398
return parseTypeSection(Ctx);
399
case wasm::WASM_SEC_IMPORT:
400
return parseImportSection(Ctx);
401
case wasm::WASM_SEC_FUNCTION:
402
return parseFunctionSection(Ctx);
403
case wasm::WASM_SEC_TABLE:
404
return parseTableSection(Ctx);
405
case wasm::WASM_SEC_MEMORY:
406
return parseMemorySection(Ctx);
407
case wasm::WASM_SEC_TAG:
408
return parseTagSection(Ctx);
409
case wasm::WASM_SEC_GLOBAL:
410
return parseGlobalSection(Ctx);
411
case wasm::WASM_SEC_EXPORT:
412
return parseExportSection(Ctx);
413
case wasm::WASM_SEC_START:
414
return parseStartSection(Ctx);
415
case wasm::WASM_SEC_ELEM:
416
return parseElemSection(Ctx);
417
case wasm::WASM_SEC_CODE:
418
return parseCodeSection(Ctx);
419
case wasm::WASM_SEC_DATA:
420
return parseDataSection(Ctx);
421
case wasm::WASM_SEC_DATACOUNT:
422
return parseDataCountSection(Ctx);
423
default:
424
return make_error<GenericBinaryError>(
425
"invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
426
}
427
}
428
429
Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
430
// Legacy "dylink" section support.
431
// See parseDylink0Section for the current "dylink.0" section parsing.
432
HasDylinkSection = true;
433
DylinkInfo.MemorySize = readVaruint32(Ctx);
434
DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
435
DylinkInfo.TableSize = readVaruint32(Ctx);
436
DylinkInfo.TableAlignment = readVaruint32(Ctx);
437
uint32_t Count = readVaruint32(Ctx);
438
while (Count--) {
439
DylinkInfo.Needed.push_back(readString(Ctx));
440
}
441
442
if (Ctx.Ptr != Ctx.End)
443
return make_error<GenericBinaryError>("dylink section ended prematurely",
444
object_error::parse_failed);
445
return Error::success();
446
}
447
448
Error WasmObjectFile::parseDylink0Section(ReadContext &Ctx) {
449
// See
450
// https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
451
HasDylinkSection = true;
452
453
const uint8_t *OrigEnd = Ctx.End;
454
while (Ctx.Ptr < OrigEnd) {
455
Ctx.End = OrigEnd;
456
uint8_t Type = readUint8(Ctx);
457
uint32_t Size = readVaruint32(Ctx);
458
LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
459
<< "\n");
460
Ctx.End = Ctx.Ptr + Size;
461
uint32_t Count;
462
switch (Type) {
463
case wasm::WASM_DYLINK_MEM_INFO:
464
DylinkInfo.MemorySize = readVaruint32(Ctx);
465
DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
466
DylinkInfo.TableSize = readVaruint32(Ctx);
467
DylinkInfo.TableAlignment = readVaruint32(Ctx);
468
break;
469
case wasm::WASM_DYLINK_NEEDED:
470
Count = readVaruint32(Ctx);
471
while (Count--) {
472
DylinkInfo.Needed.push_back(readString(Ctx));
473
}
474
break;
475
case wasm::WASM_DYLINK_EXPORT_INFO: {
476
uint32_t Count = readVaruint32(Ctx);
477
while (Count--) {
478
DylinkInfo.ExportInfo.push_back({readString(Ctx), readVaruint32(Ctx)});
479
}
480
break;
481
}
482
case wasm::WASM_DYLINK_IMPORT_INFO: {
483
uint32_t Count = readVaruint32(Ctx);
484
while (Count--) {
485
DylinkInfo.ImportInfo.push_back(
486
{readString(Ctx), readString(Ctx), readVaruint32(Ctx)});
487
}
488
break;
489
}
490
default:
491
LLVM_DEBUG(dbgs() << "unknown dylink.0 sub-section: " << Type << "\n");
492
Ctx.Ptr += Size;
493
break;
494
}
495
if (Ctx.Ptr != Ctx.End) {
496
return make_error<GenericBinaryError>(
497
"dylink.0 sub-section ended prematurely", object_error::parse_failed);
498
}
499
}
500
501
if (Ctx.Ptr != Ctx.End)
502
return make_error<GenericBinaryError>("dylink.0 section ended prematurely",
503
object_error::parse_failed);
504
return Error::success();
505
}
506
507
Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
508
llvm::DenseSet<uint64_t> SeenFunctions;
509
llvm::DenseSet<uint64_t> SeenGlobals;
510
llvm::DenseSet<uint64_t> SeenSegments;
511
512
// If we have linking section (symbol table) or if we are parsing a DSO
513
// then we don't use the name section for symbol information.
514
bool PopulateSymbolTable = !HasLinkingSection && !HasDylinkSection;
515
516
// If we are using the name section for symbol information then it will
517
// supersede any symbols created by the export section.
518
if (PopulateSymbolTable)
519
Symbols.clear();
520
521
while (Ctx.Ptr < Ctx.End) {
522
uint8_t Type = readUint8(Ctx);
523
uint32_t Size = readVaruint32(Ctx);
524
const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
525
526
switch (Type) {
527
case wasm::WASM_NAMES_FUNCTION:
528
case wasm::WASM_NAMES_GLOBAL:
529
case wasm::WASM_NAMES_DATA_SEGMENT: {
530
uint32_t Count = readVaruint32(Ctx);
531
while (Count--) {
532
uint32_t Index = readVaruint32(Ctx);
533
StringRef Name = readString(Ctx);
534
wasm::NameType nameType = wasm::NameType::FUNCTION;
535
wasm::WasmSymbolInfo Info{Name,
536
/*Kind */ wasm::WASM_SYMBOL_TYPE_FUNCTION,
537
/* Flags */ 0,
538
/* ImportModule */ std::nullopt,
539
/* ImportName */ std::nullopt,
540
/* ExportName */ std::nullopt,
541
{/* ElementIndex */ Index}};
542
const wasm::WasmSignature *Signature = nullptr;
543
const wasm::WasmGlobalType *GlobalType = nullptr;
544
const wasm::WasmTableType *TableType = nullptr;
545
if (Type == wasm::WASM_NAMES_FUNCTION) {
546
if (!SeenFunctions.insert(Index).second)
547
return make_error<GenericBinaryError>(
548
"function named more than once", object_error::parse_failed);
549
if (!isValidFunctionIndex(Index) || Name.empty())
550
return make_error<GenericBinaryError>("invalid function name entry",
551
object_error::parse_failed);
552
553
if (isDefinedFunctionIndex(Index)) {
554
wasm::WasmFunction &F = getDefinedFunction(Index);
555
F.DebugName = Name;
556
Signature = &Signatures[F.SigIndex];
557
if (F.ExportName) {
558
Info.ExportName = F.ExportName;
559
Info.Flags |= wasm::WASM_SYMBOL_BINDING_GLOBAL;
560
} else {
561
Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
562
}
563
} else {
564
Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
565
}
566
} else if (Type == wasm::WASM_NAMES_GLOBAL) {
567
if (!SeenGlobals.insert(Index).second)
568
return make_error<GenericBinaryError>("global named more than once",
569
object_error::parse_failed);
570
if (!isValidGlobalIndex(Index) || Name.empty())
571
return make_error<GenericBinaryError>("invalid global name entry",
572
object_error::parse_failed);
573
nameType = wasm::NameType::GLOBAL;
574
Info.Kind = wasm::WASM_SYMBOL_TYPE_GLOBAL;
575
if (isDefinedGlobalIndex(Index)) {
576
GlobalType = &getDefinedGlobal(Index).Type;
577
} else {
578
Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
579
}
580
} else {
581
if (!SeenSegments.insert(Index).second)
582
return make_error<GenericBinaryError>(
583
"segment named more than once", object_error::parse_failed);
584
if (Index > DataSegments.size())
585
return make_error<GenericBinaryError>("invalid data segment name entry",
586
object_error::parse_failed);
587
nameType = wasm::NameType::DATA_SEGMENT;
588
Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
589
Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
590
assert(Index < DataSegments.size());
591
Info.DataRef = wasm::WasmDataReference{
592
Index, 0, DataSegments[Index].Data.Content.size()};
593
}
594
DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
595
if (PopulateSymbolTable)
596
Symbols.emplace_back(Info, GlobalType, TableType, Signature);
597
}
598
break;
599
}
600
// Ignore local names for now
601
case wasm::WASM_NAMES_LOCAL:
602
default:
603
Ctx.Ptr += Size;
604
break;
605
}
606
if (Ctx.Ptr != SubSectionEnd)
607
return make_error<GenericBinaryError>(
608
"name sub-section ended prematurely", object_error::parse_failed);
609
}
610
611
if (Ctx.Ptr != Ctx.End)
612
return make_error<GenericBinaryError>("name section ended prematurely",
613
object_error::parse_failed);
614
return Error::success();
615
}
616
617
Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
618
HasLinkingSection = true;
619
620
LinkingData.Version = readVaruint32(Ctx);
621
if (LinkingData.Version != wasm::WasmMetadataVersion) {
622
return make_error<GenericBinaryError>(
623
"unexpected metadata version: " + Twine(LinkingData.Version) +
624
" (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
625
object_error::parse_failed);
626
}
627
628
const uint8_t *OrigEnd = Ctx.End;
629
while (Ctx.Ptr < OrigEnd) {
630
Ctx.End = OrigEnd;
631
uint8_t Type = readUint8(Ctx);
632
uint32_t Size = readVaruint32(Ctx);
633
LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
634
<< "\n");
635
Ctx.End = Ctx.Ptr + Size;
636
switch (Type) {
637
case wasm::WASM_SYMBOL_TABLE:
638
if (Error Err = parseLinkingSectionSymtab(Ctx))
639
return Err;
640
break;
641
case wasm::WASM_SEGMENT_INFO: {
642
uint32_t Count = readVaruint32(Ctx);
643
if (Count > DataSegments.size())
644
return make_error<GenericBinaryError>("too many segment names",
645
object_error::parse_failed);
646
for (uint32_t I = 0; I < Count; I++) {
647
DataSegments[I].Data.Name = readString(Ctx);
648
DataSegments[I].Data.Alignment = readVaruint32(Ctx);
649
DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
650
}
651
break;
652
}
653
case wasm::WASM_INIT_FUNCS: {
654
uint32_t Count = readVaruint32(Ctx);
655
LinkingData.InitFunctions.reserve(Count);
656
for (uint32_t I = 0; I < Count; I++) {
657
wasm::WasmInitFunc Init;
658
Init.Priority = readVaruint32(Ctx);
659
Init.Symbol = readVaruint32(Ctx);
660
if (!isValidFunctionSymbol(Init.Symbol))
661
return make_error<GenericBinaryError>("invalid function symbol: " +
662
Twine(Init.Symbol),
663
object_error::parse_failed);
664
LinkingData.InitFunctions.emplace_back(Init);
665
}
666
break;
667
}
668
case wasm::WASM_COMDAT_INFO:
669
if (Error Err = parseLinkingSectionComdat(Ctx))
670
return Err;
671
break;
672
default:
673
Ctx.Ptr += Size;
674
break;
675
}
676
if (Ctx.Ptr != Ctx.End)
677
return make_error<GenericBinaryError>(
678
"linking sub-section ended prematurely", object_error::parse_failed);
679
}
680
if (Ctx.Ptr != OrigEnd)
681
return make_error<GenericBinaryError>("linking section ended prematurely",
682
object_error::parse_failed);
683
return Error::success();
684
}
685
686
Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
687
uint32_t Count = readVaruint32(Ctx);
688
// Clear out any symbol information that was derived from the exports
689
// section.
690
Symbols.clear();
691
Symbols.reserve(Count);
692
StringSet<> SymbolNames;
693
694
std::vector<wasm::WasmImport *> ImportedGlobals;
695
std::vector<wasm::WasmImport *> ImportedFunctions;
696
std::vector<wasm::WasmImport *> ImportedTags;
697
std::vector<wasm::WasmImport *> ImportedTables;
698
ImportedGlobals.reserve(Imports.size());
699
ImportedFunctions.reserve(Imports.size());
700
ImportedTags.reserve(Imports.size());
701
ImportedTables.reserve(Imports.size());
702
for (auto &I : Imports) {
703
if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
704
ImportedFunctions.emplace_back(&I);
705
else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
706
ImportedGlobals.emplace_back(&I);
707
else if (I.Kind == wasm::WASM_EXTERNAL_TAG)
708
ImportedTags.emplace_back(&I);
709
else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
710
ImportedTables.emplace_back(&I);
711
}
712
713
while (Count--) {
714
wasm::WasmSymbolInfo Info;
715
const wasm::WasmSignature *Signature = nullptr;
716
const wasm::WasmGlobalType *GlobalType = nullptr;
717
const wasm::WasmTableType *TableType = nullptr;
718
719
Info.Kind = readUint8(Ctx);
720
Info.Flags = readVaruint32(Ctx);
721
bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
722
723
switch (Info.Kind) {
724
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
725
Info.ElementIndex = readVaruint32(Ctx);
726
if (!isValidFunctionIndex(Info.ElementIndex) ||
727
IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
728
return make_error<GenericBinaryError>("invalid function symbol index",
729
object_error::parse_failed);
730
if (IsDefined) {
731
Info.Name = readString(Ctx);
732
unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
733
wasm::WasmFunction &Function = Functions[FuncIndex];
734
Signature = &Signatures[Function.SigIndex];
735
if (Function.SymbolName.empty())
736
Function.SymbolName = Info.Name;
737
} else {
738
wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
739
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
740
Info.Name = readString(Ctx);
741
Info.ImportName = Import.Field;
742
} else {
743
Info.Name = Import.Field;
744
}
745
Signature = &Signatures[Import.SigIndex];
746
Info.ImportModule = Import.Module;
747
}
748
break;
749
750
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
751
Info.ElementIndex = readVaruint32(Ctx);
752
if (!isValidGlobalIndex(Info.ElementIndex) ||
753
IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
754
return make_error<GenericBinaryError>("invalid global symbol index",
755
object_error::parse_failed);
756
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
757
wasm::WASM_SYMBOL_BINDING_WEAK)
758
return make_error<GenericBinaryError>("undefined weak global symbol",
759
object_error::parse_failed);
760
if (IsDefined) {
761
Info.Name = readString(Ctx);
762
unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
763
wasm::WasmGlobal &Global = Globals[GlobalIndex];
764
GlobalType = &Global.Type;
765
if (Global.SymbolName.empty())
766
Global.SymbolName = Info.Name;
767
} else {
768
wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
769
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
770
Info.Name = readString(Ctx);
771
Info.ImportName = Import.Field;
772
} else {
773
Info.Name = Import.Field;
774
}
775
GlobalType = &Import.Global;
776
Info.ImportModule = Import.Module;
777
}
778
break;
779
780
case wasm::WASM_SYMBOL_TYPE_TABLE:
781
Info.ElementIndex = readVaruint32(Ctx);
782
if (!isValidTableNumber(Info.ElementIndex) ||
783
IsDefined != isDefinedTableNumber(Info.ElementIndex))
784
return make_error<GenericBinaryError>("invalid table symbol index",
785
object_error::parse_failed);
786
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
787
wasm::WASM_SYMBOL_BINDING_WEAK)
788
return make_error<GenericBinaryError>("undefined weak table symbol",
789
object_error::parse_failed);
790
if (IsDefined) {
791
Info.Name = readString(Ctx);
792
unsigned TableNumber = Info.ElementIndex - NumImportedTables;
793
wasm::WasmTable &Table = Tables[TableNumber];
794
TableType = &Table.Type;
795
if (Table.SymbolName.empty())
796
Table.SymbolName = Info.Name;
797
} else {
798
wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
799
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
800
Info.Name = readString(Ctx);
801
Info.ImportName = Import.Field;
802
} else {
803
Info.Name = Import.Field;
804
}
805
TableType = &Import.Table;
806
Info.ImportModule = Import.Module;
807
}
808
break;
809
810
case wasm::WASM_SYMBOL_TYPE_DATA:
811
Info.Name = readString(Ctx);
812
if (IsDefined) {
813
auto Index = readVaruint32(Ctx);
814
auto Offset = readVaruint64(Ctx);
815
auto Size = readVaruint64(Ctx);
816
if (!(Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE)) {
817
if (static_cast<size_t>(Index) >= DataSegments.size())
818
return make_error<GenericBinaryError>(
819
"invalid data segment index: " + Twine(Index),
820
object_error::parse_failed);
821
size_t SegmentSize = DataSegments[Index].Data.Content.size();
822
if (Offset > SegmentSize)
823
return make_error<GenericBinaryError>(
824
"invalid data symbol offset: `" + Info.Name +
825
"` (offset: " + Twine(Offset) +
826
" segment size: " + Twine(SegmentSize) + ")",
827
object_error::parse_failed);
828
}
829
Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
830
}
831
break;
832
833
case wasm::WASM_SYMBOL_TYPE_SECTION: {
834
if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
835
wasm::WASM_SYMBOL_BINDING_LOCAL)
836
return make_error<GenericBinaryError>(
837
"section symbols must have local binding",
838
object_error::parse_failed);
839
Info.ElementIndex = readVaruint32(Ctx);
840
// Use somewhat unique section name as symbol name.
841
StringRef SectionName = Sections[Info.ElementIndex].Name;
842
Info.Name = SectionName;
843
break;
844
}
845
846
case wasm::WASM_SYMBOL_TYPE_TAG: {
847
Info.ElementIndex = readVaruint32(Ctx);
848
if (!isValidTagIndex(Info.ElementIndex) ||
849
IsDefined != isDefinedTagIndex(Info.ElementIndex))
850
return make_error<GenericBinaryError>("invalid tag symbol index",
851
object_error::parse_failed);
852
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
853
wasm::WASM_SYMBOL_BINDING_WEAK)
854
return make_error<GenericBinaryError>("undefined weak global symbol",
855
object_error::parse_failed);
856
if (IsDefined) {
857
Info.Name = readString(Ctx);
858
unsigned TagIndex = Info.ElementIndex - NumImportedTags;
859
wasm::WasmTag &Tag = Tags[TagIndex];
860
Signature = &Signatures[Tag.SigIndex];
861
if (Tag.SymbolName.empty())
862
Tag.SymbolName = Info.Name;
863
864
} else {
865
wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
866
if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
867
Info.Name = readString(Ctx);
868
Info.ImportName = Import.Field;
869
} else {
870
Info.Name = Import.Field;
871
}
872
Signature = &Signatures[Import.SigIndex];
873
Info.ImportModule = Import.Module;
874
}
875
break;
876
}
877
878
default:
879
return make_error<GenericBinaryError>("invalid symbol type: " +
880
Twine(unsigned(Info.Kind)),
881
object_error::parse_failed);
882
}
883
884
if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
885
wasm::WASM_SYMBOL_BINDING_LOCAL &&
886
!SymbolNames.insert(Info.Name).second)
887
return make_error<GenericBinaryError>("duplicate symbol name " +
888
Twine(Info.Name),
889
object_error::parse_failed);
890
Symbols.emplace_back(Info, GlobalType, TableType, Signature);
891
LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
892
}
893
894
return Error::success();
895
}
896
897
Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
898
uint32_t ComdatCount = readVaruint32(Ctx);
899
StringSet<> ComdatSet;
900
for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
901
StringRef Name = readString(Ctx);
902
if (Name.empty() || !ComdatSet.insert(Name).second)
903
return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
904
Twine(Name),
905
object_error::parse_failed);
906
LinkingData.Comdats.emplace_back(Name);
907
uint32_t Flags = readVaruint32(Ctx);
908
if (Flags != 0)
909
return make_error<GenericBinaryError>("unsupported COMDAT flags",
910
object_error::parse_failed);
911
912
uint32_t EntryCount = readVaruint32(Ctx);
913
while (EntryCount--) {
914
unsigned Kind = readVaruint32(Ctx);
915
unsigned Index = readVaruint32(Ctx);
916
switch (Kind) {
917
default:
918
return make_error<GenericBinaryError>("invalid COMDAT entry type",
919
object_error::parse_failed);
920
case wasm::WASM_COMDAT_DATA:
921
if (Index >= DataSegments.size())
922
return make_error<GenericBinaryError>(
923
"COMDAT data index out of range", object_error::parse_failed);
924
if (DataSegments[Index].Data.Comdat != UINT32_MAX)
925
return make_error<GenericBinaryError>("data segment in two COMDATs",
926
object_error::parse_failed);
927
DataSegments[Index].Data.Comdat = ComdatIndex;
928
break;
929
case wasm::WASM_COMDAT_FUNCTION:
930
if (!isDefinedFunctionIndex(Index))
931
return make_error<GenericBinaryError>(
932
"COMDAT function index out of range", object_error::parse_failed);
933
if (getDefinedFunction(Index).Comdat != UINT32_MAX)
934
return make_error<GenericBinaryError>("function in two COMDATs",
935
object_error::parse_failed);
936
getDefinedFunction(Index).Comdat = ComdatIndex;
937
break;
938
case wasm::WASM_COMDAT_SECTION:
939
if (Index >= Sections.size())
940
return make_error<GenericBinaryError>(
941
"COMDAT section index out of range", object_error::parse_failed);
942
if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
943
return make_error<GenericBinaryError>(
944
"non-custom section in a COMDAT", object_error::parse_failed);
945
Sections[Index].Comdat = ComdatIndex;
946
break;
947
}
948
}
949
}
950
return Error::success();
951
}
952
953
Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
954
llvm::SmallSet<StringRef, 3> FieldsSeen;
955
uint32_t Fields = readVaruint32(Ctx);
956
for (size_t I = 0; I < Fields; ++I) {
957
StringRef FieldName = readString(Ctx);
958
if (!FieldsSeen.insert(FieldName).second)
959
return make_error<GenericBinaryError>(
960
"producers section does not have unique fields",
961
object_error::parse_failed);
962
std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
963
if (FieldName == "language") {
964
ProducerVec = &ProducerInfo.Languages;
965
} else if (FieldName == "processed-by") {
966
ProducerVec = &ProducerInfo.Tools;
967
} else if (FieldName == "sdk") {
968
ProducerVec = &ProducerInfo.SDKs;
969
} else {
970
return make_error<GenericBinaryError>(
971
"producers section field is not named one of language, processed-by, "
972
"or sdk",
973
object_error::parse_failed);
974
}
975
uint32_t ValueCount = readVaruint32(Ctx);
976
llvm::SmallSet<StringRef, 8> ProducersSeen;
977
for (size_t J = 0; J < ValueCount; ++J) {
978
StringRef Name = readString(Ctx);
979
StringRef Version = readString(Ctx);
980
if (!ProducersSeen.insert(Name).second) {
981
return make_error<GenericBinaryError>(
982
"producers section contains repeated producer",
983
object_error::parse_failed);
984
}
985
ProducerVec->emplace_back(std::string(Name), std::string(Version));
986
}
987
}
988
if (Ctx.Ptr != Ctx.End)
989
return make_error<GenericBinaryError>("producers section ended prematurely",
990
object_error::parse_failed);
991
return Error::success();
992
}
993
994
Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
995
llvm::SmallSet<std::string, 8> FeaturesSeen;
996
uint32_t FeatureCount = readVaruint32(Ctx);
997
for (size_t I = 0; I < FeatureCount; ++I) {
998
wasm::WasmFeatureEntry Feature;
999
Feature.Prefix = readUint8(Ctx);
1000
switch (Feature.Prefix) {
1001
case wasm::WASM_FEATURE_PREFIX_USED:
1002
case wasm::WASM_FEATURE_PREFIX_REQUIRED:
1003
case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
1004
break;
1005
default:
1006
return make_error<GenericBinaryError>("unknown feature policy prefix",
1007
object_error::parse_failed);
1008
}
1009
Feature.Name = std::string(readString(Ctx));
1010
if (!FeaturesSeen.insert(Feature.Name).second)
1011
return make_error<GenericBinaryError>(
1012
"target features section contains repeated feature \"" +
1013
Feature.Name + "\"",
1014
object_error::parse_failed);
1015
TargetFeatures.push_back(Feature);
1016
}
1017
if (Ctx.Ptr != Ctx.End)
1018
return make_error<GenericBinaryError>(
1019
"target features section ended prematurely",
1020
object_error::parse_failed);
1021
return Error::success();
1022
}
1023
1024
Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
1025
uint32_t SectionIndex = readVaruint32(Ctx);
1026
if (SectionIndex >= Sections.size())
1027
return make_error<GenericBinaryError>("invalid section index",
1028
object_error::parse_failed);
1029
WasmSection &Section = Sections[SectionIndex];
1030
uint32_t RelocCount = readVaruint32(Ctx);
1031
uint32_t EndOffset = Section.Content.size();
1032
uint32_t PreviousOffset = 0;
1033
while (RelocCount--) {
1034
wasm::WasmRelocation Reloc = {};
1035
uint32_t type = readVaruint32(Ctx);
1036
Reloc.Type = type;
1037
Reloc.Offset = readVaruint32(Ctx);
1038
if (Reloc.Offset < PreviousOffset)
1039
return make_error<GenericBinaryError>("relocations not in offset order",
1040
object_error::parse_failed);
1041
1042
auto badReloc = [&](StringRef msg) {
1043
return make_error<GenericBinaryError>(
1044
msg + ": " + Twine(Symbols[Reloc.Index].Info.Name),
1045
object_error::parse_failed);
1046
};
1047
1048
PreviousOffset = Reloc.Offset;
1049
Reloc.Index = readVaruint32(Ctx);
1050
switch (type) {
1051
case wasm::R_WASM_FUNCTION_INDEX_LEB:
1052
case wasm::R_WASM_FUNCTION_INDEX_I32:
1053
case wasm::R_WASM_TABLE_INDEX_SLEB:
1054
case wasm::R_WASM_TABLE_INDEX_SLEB64:
1055
case wasm::R_WASM_TABLE_INDEX_I32:
1056
case wasm::R_WASM_TABLE_INDEX_I64:
1057
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
1058
case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
1059
if (!isValidFunctionSymbol(Reloc.Index))
1060
return badReloc("invalid function relocation");
1061
break;
1062
case wasm::R_WASM_TABLE_NUMBER_LEB:
1063
if (!isValidTableSymbol(Reloc.Index))
1064
return badReloc("invalid table relocation");
1065
break;
1066
case wasm::R_WASM_TYPE_INDEX_LEB:
1067
if (Reloc.Index >= Signatures.size())
1068
return badReloc("invalid relocation type index");
1069
break;
1070
case wasm::R_WASM_GLOBAL_INDEX_LEB:
1071
// R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
1072
// symbols to refer to their GOT entries.
1073
if (!isValidGlobalSymbol(Reloc.Index) &&
1074
!isValidDataSymbol(Reloc.Index) &&
1075
!isValidFunctionSymbol(Reloc.Index))
1076
return badReloc("invalid global relocation");
1077
break;
1078
case wasm::R_WASM_GLOBAL_INDEX_I32:
1079
if (!isValidGlobalSymbol(Reloc.Index))
1080
return badReloc("invalid global relocation");
1081
break;
1082
case wasm::R_WASM_TAG_INDEX_LEB:
1083
if (!isValidTagSymbol(Reloc.Index))
1084
return badReloc("invalid tag relocation");
1085
break;
1086
case wasm::R_WASM_MEMORY_ADDR_LEB:
1087
case wasm::R_WASM_MEMORY_ADDR_SLEB:
1088
case wasm::R_WASM_MEMORY_ADDR_I32:
1089
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
1090
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
1091
case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
1092
if (!isValidDataSymbol(Reloc.Index))
1093
return badReloc("invalid data relocation");
1094
Reloc.Addend = readVarint32(Ctx);
1095
break;
1096
case wasm::R_WASM_MEMORY_ADDR_LEB64:
1097
case wasm::R_WASM_MEMORY_ADDR_SLEB64:
1098
case wasm::R_WASM_MEMORY_ADDR_I64:
1099
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
1100
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
1101
if (!isValidDataSymbol(Reloc.Index))
1102
return badReloc("invalid data relocation");
1103
Reloc.Addend = readVarint64(Ctx);
1104
break;
1105
case wasm::R_WASM_FUNCTION_OFFSET_I32:
1106
if (!isValidFunctionSymbol(Reloc.Index))
1107
return badReloc("invalid function relocation");
1108
Reloc.Addend = readVarint32(Ctx);
1109
break;
1110
case wasm::R_WASM_FUNCTION_OFFSET_I64:
1111
if (!isValidFunctionSymbol(Reloc.Index))
1112
return badReloc("invalid function relocation");
1113
Reloc.Addend = readVarint64(Ctx);
1114
break;
1115
case wasm::R_WASM_SECTION_OFFSET_I32:
1116
if (!isValidSectionSymbol(Reloc.Index))
1117
return badReloc("invalid section relocation");
1118
Reloc.Addend = readVarint32(Ctx);
1119
break;
1120
default:
1121
return make_error<GenericBinaryError>("invalid relocation type: " +
1122
Twine(type),
1123
object_error::parse_failed);
1124
}
1125
1126
// Relocations must fit inside the section, and must appear in order. They
1127
// also shouldn't overlap a function/element boundary, but we don't bother
1128
// to check that.
1129
uint64_t Size = 5;
1130
if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
1131
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
1132
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
1133
Size = 10;
1134
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
1135
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
1136
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
1137
Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
1138
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
1139
Reloc.Type == wasm::R_WASM_FUNCTION_INDEX_I32 ||
1140
Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
1141
Size = 4;
1142
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
1143
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
1144
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
1145
Size = 8;
1146
if (Reloc.Offset + Size > EndOffset)
1147
return make_error<GenericBinaryError>("invalid relocation offset",
1148
object_error::parse_failed);
1149
1150
Section.Relocations.push_back(Reloc);
1151
}
1152
if (Ctx.Ptr != Ctx.End)
1153
return make_error<GenericBinaryError>("reloc section ended prematurely",
1154
object_error::parse_failed);
1155
return Error::success();
1156
}
1157
1158
Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
1159
if (Sec.Name == "dylink") {
1160
if (Error Err = parseDylinkSection(Ctx))
1161
return Err;
1162
} else if (Sec.Name == "dylink.0") {
1163
if (Error Err = parseDylink0Section(Ctx))
1164
return Err;
1165
} else if (Sec.Name == "name") {
1166
if (Error Err = parseNameSection(Ctx))
1167
return Err;
1168
} else if (Sec.Name == "linking") {
1169
if (Error Err = parseLinkingSection(Ctx))
1170
return Err;
1171
} else if (Sec.Name == "producers") {
1172
if (Error Err = parseProducersSection(Ctx))
1173
return Err;
1174
} else if (Sec.Name == "target_features") {
1175
if (Error Err = parseTargetFeaturesSection(Ctx))
1176
return Err;
1177
} else if (Sec.Name.starts_with("reloc.")) {
1178
if (Error Err = parseRelocSection(Sec.Name, Ctx))
1179
return Err;
1180
}
1181
return Error::success();
1182
}
1183
1184
Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1185
auto parseFieldDef = [&]() {
1186
uint32_t TypeCode = readVaruint32((Ctx));
1187
/* Discard StorageType */ parseValType(Ctx, TypeCode);
1188
/* Discard Mutability */ readVaruint32(Ctx);
1189
};
1190
1191
uint32_t Count = readVaruint32(Ctx);
1192
Signatures.reserve(Count);
1193
while (Count--) {
1194
wasm::WasmSignature Sig;
1195
uint8_t Form = readUint8(Ctx);
1196
if (Form == wasm::WASM_TYPE_REC) {
1197
// Rec groups expand the type index space (beyond what was declared at
1198
// the top of the section, and also consume one element in that space.
1199
uint32_t RecSize = readVaruint32(Ctx);
1200
if (RecSize == 0)
1201
return make_error<GenericBinaryError>("Rec group size cannot be 0",
1202
object_error::parse_failed);
1203
Signatures.reserve(Signatures.size() + RecSize);
1204
Count += RecSize;
1205
Sig.Kind = wasm::WasmSignature::Placeholder;
1206
Signatures.push_back(std::move(Sig));
1207
HasUnmodeledTypes = true;
1208
continue;
1209
}
1210
if (Form != wasm::WASM_TYPE_FUNC) {
1211
// Currently LLVM only models function types, and not other composite
1212
// types. Here we parse the type declarations just enough to skip past
1213
// them in the binary.
1214
if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
1215
uint32_t Supers = readVaruint32(Ctx);
1216
if (Supers > 0) {
1217
if (Supers != 1)
1218
return make_error<GenericBinaryError>(
1219
"Invalid number of supertypes", object_error::parse_failed);
1220
/* Discard SuperIndex */ readVaruint32(Ctx);
1221
}
1222
Form = readVaruint32(Ctx);
1223
}
1224
if (Form == wasm::WASM_TYPE_STRUCT) {
1225
uint32_t FieldCount = readVaruint32(Ctx);
1226
while (FieldCount--) {
1227
parseFieldDef();
1228
}
1229
} else if (Form == wasm::WASM_TYPE_ARRAY) {
1230
parseFieldDef();
1231
} else {
1232
return make_error<GenericBinaryError>("bad form",
1233
object_error::parse_failed);
1234
}
1235
Sig.Kind = wasm::WasmSignature::Placeholder;
1236
Signatures.push_back(std::move(Sig));
1237
HasUnmodeledTypes = true;
1238
continue;
1239
}
1240
1241
uint32_t ParamCount = readVaruint32(Ctx);
1242
Sig.Params.reserve(ParamCount);
1243
while (ParamCount--) {
1244
uint32_t ParamType = readUint8(Ctx);
1245
Sig.Params.push_back(parseValType(Ctx, ParamType));
1246
continue;
1247
}
1248
uint32_t ReturnCount = readVaruint32(Ctx);
1249
while (ReturnCount--) {
1250
uint32_t ReturnType = readUint8(Ctx);
1251
Sig.Returns.push_back(parseValType(Ctx, ReturnType));
1252
}
1253
1254
Signatures.push_back(std::move(Sig));
1255
}
1256
if (Ctx.Ptr != Ctx.End)
1257
return make_error<GenericBinaryError>("type section ended prematurely",
1258
object_error::parse_failed);
1259
return Error::success();
1260
}
1261
1262
Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1263
uint32_t Count = readVaruint32(Ctx);
1264
uint32_t NumTypes = Signatures.size();
1265
Imports.reserve(Count);
1266
for (uint32_t I = 0; I < Count; I++) {
1267
wasm::WasmImport Im;
1268
Im.Module = readString(Ctx);
1269
Im.Field = readString(Ctx);
1270
Im.Kind = readUint8(Ctx);
1271
switch (Im.Kind) {
1272
case wasm::WASM_EXTERNAL_FUNCTION:
1273
NumImportedFunctions++;
1274
Im.SigIndex = readVaruint32(Ctx);
1275
if (Im.SigIndex >= NumTypes)
1276
return make_error<GenericBinaryError>("invalid function type",
1277
object_error::parse_failed);
1278
break;
1279
case wasm::WASM_EXTERNAL_GLOBAL:
1280
NumImportedGlobals++;
1281
Im.Global.Type = readUint8(Ctx);
1282
Im.Global.Mutable = readVaruint1(Ctx);
1283
break;
1284
case wasm::WASM_EXTERNAL_MEMORY:
1285
Im.Memory = readLimits(Ctx);
1286
if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1287
HasMemory64 = true;
1288
break;
1289
case wasm::WASM_EXTERNAL_TABLE: {
1290
Im.Table = readTableType(Ctx);
1291
NumImportedTables++;
1292
auto ElemType = Im.Table.ElemType;
1293
if (ElemType != wasm::ValType::FUNCREF &&
1294
ElemType != wasm::ValType::EXTERNREF &&
1295
ElemType != wasm::ValType::EXNREF &&
1296
ElemType != wasm::ValType::OTHERREF)
1297
return make_error<GenericBinaryError>("invalid table element type",
1298
object_error::parse_failed);
1299
break;
1300
}
1301
case wasm::WASM_EXTERNAL_TAG:
1302
NumImportedTags++;
1303
if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1304
return make_error<GenericBinaryError>("invalid attribute",
1305
object_error::parse_failed);
1306
Im.SigIndex = readVaruint32(Ctx);
1307
if (Im.SigIndex >= NumTypes)
1308
return make_error<GenericBinaryError>("invalid tag type",
1309
object_error::parse_failed);
1310
break;
1311
default:
1312
return make_error<GenericBinaryError>("unexpected import kind",
1313
object_error::parse_failed);
1314
}
1315
Imports.push_back(Im);
1316
}
1317
if (Ctx.Ptr != Ctx.End)
1318
return make_error<GenericBinaryError>("import section ended prematurely",
1319
object_error::parse_failed);
1320
return Error::success();
1321
}
1322
1323
Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1324
uint32_t Count = readVaruint32(Ctx);
1325
Functions.reserve(Count);
1326
uint32_t NumTypes = Signatures.size();
1327
while (Count--) {
1328
uint32_t Type = readVaruint32(Ctx);
1329
if (Type >= NumTypes)
1330
return make_error<GenericBinaryError>("invalid function type",
1331
object_error::parse_failed);
1332
wasm::WasmFunction F;
1333
F.SigIndex = Type;
1334
Functions.push_back(F);
1335
}
1336
if (Ctx.Ptr != Ctx.End)
1337
return make_error<GenericBinaryError>("function section ended prematurely",
1338
object_error::parse_failed);
1339
return Error::success();
1340
}
1341
1342
Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1343
TableSection = Sections.size();
1344
uint32_t Count = readVaruint32(Ctx);
1345
Tables.reserve(Count);
1346
while (Count--) {
1347
wasm::WasmTable T;
1348
T.Type = readTableType(Ctx);
1349
T.Index = NumImportedTables + Tables.size();
1350
Tables.push_back(T);
1351
auto ElemType = Tables.back().Type.ElemType;
1352
if (ElemType != wasm::ValType::FUNCREF &&
1353
ElemType != wasm::ValType::EXTERNREF &&
1354
ElemType != wasm::ValType::EXNREF &&
1355
ElemType != wasm::ValType::OTHERREF) {
1356
return make_error<GenericBinaryError>("invalid table element type",
1357
object_error::parse_failed);
1358
}
1359
}
1360
if (Ctx.Ptr != Ctx.End)
1361
return make_error<GenericBinaryError>("table section ended prematurely",
1362
object_error::parse_failed);
1363
return Error::success();
1364
}
1365
1366
Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1367
uint32_t Count = readVaruint32(Ctx);
1368
Memories.reserve(Count);
1369
while (Count--) {
1370
auto Limits = readLimits(Ctx);
1371
if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1372
HasMemory64 = true;
1373
Memories.push_back(Limits);
1374
}
1375
if (Ctx.Ptr != Ctx.End)
1376
return make_error<GenericBinaryError>("memory section ended prematurely",
1377
object_error::parse_failed);
1378
return Error::success();
1379
}
1380
1381
Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
1382
TagSection = Sections.size();
1383
uint32_t Count = readVaruint32(Ctx);
1384
Tags.reserve(Count);
1385
uint32_t NumTypes = Signatures.size();
1386
while (Count--) {
1387
if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1388
return make_error<GenericBinaryError>("invalid attribute",
1389
object_error::parse_failed);
1390
uint32_t Type = readVaruint32(Ctx);
1391
if (Type >= NumTypes)
1392
return make_error<GenericBinaryError>("invalid tag type",
1393
object_error::parse_failed);
1394
wasm::WasmTag Tag;
1395
Tag.Index = NumImportedTags + Tags.size();
1396
Tag.SigIndex = Type;
1397
Signatures[Type].Kind = wasm::WasmSignature::Tag;
1398
Tags.push_back(Tag);
1399
}
1400
1401
if (Ctx.Ptr != Ctx.End)
1402
return make_error<GenericBinaryError>("tag section ended prematurely",
1403
object_error::parse_failed);
1404
return Error::success();
1405
}
1406
1407
Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1408
GlobalSection = Sections.size();
1409
const uint8_t *SectionStart = Ctx.Ptr;
1410
uint32_t Count = readVaruint32(Ctx);
1411
Globals.reserve(Count);
1412
while (Count--) {
1413
wasm::WasmGlobal Global;
1414
Global.Index = NumImportedGlobals + Globals.size();
1415
const uint8_t *GlobalStart = Ctx.Ptr;
1416
Global.Offset = static_cast<uint32_t>(GlobalStart - SectionStart);
1417
auto GlobalOpcode = readVaruint32(Ctx);
1418
Global.Type.Type = (uint8_t)parseValType(Ctx, GlobalOpcode);
1419
Global.Type.Mutable = readVaruint1(Ctx);
1420
if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1421
return Err;
1422
Global.Size = static_cast<uint32_t>(Ctx.Ptr - GlobalStart);
1423
Globals.push_back(Global);
1424
}
1425
if (Ctx.Ptr != Ctx.End)
1426
return make_error<GenericBinaryError>("global section ended prematurely",
1427
object_error::parse_failed);
1428
return Error::success();
1429
}
1430
1431
Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1432
uint32_t Count = readVaruint32(Ctx);
1433
Exports.reserve(Count);
1434
Symbols.reserve(Count);
1435
for (uint32_t I = 0; I < Count; I++) {
1436
wasm::WasmExport Ex;
1437
Ex.Name = readString(Ctx);
1438
Ex.Kind = readUint8(Ctx);
1439
Ex.Index = readVaruint32(Ctx);
1440
const wasm::WasmSignature *Signature = nullptr;
1441
const wasm::WasmGlobalType *GlobalType = nullptr;
1442
const wasm::WasmTableType *TableType = nullptr;
1443
wasm::WasmSymbolInfo Info;
1444
Info.Name = Ex.Name;
1445
Info.Flags = 0;
1446
switch (Ex.Kind) {
1447
case wasm::WASM_EXTERNAL_FUNCTION: {
1448
if (!isDefinedFunctionIndex(Ex.Index))
1449
return make_error<GenericBinaryError>("invalid function export",
1450
object_error::parse_failed);
1451
getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1452
Info.Kind = wasm::WASM_SYMBOL_TYPE_FUNCTION;
1453
Info.ElementIndex = Ex.Index;
1454
unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
1455
wasm::WasmFunction &Function = Functions[FuncIndex];
1456
Signature = &Signatures[Function.SigIndex];
1457
break;
1458
}
1459
case wasm::WASM_EXTERNAL_GLOBAL: {
1460
if (!isValidGlobalIndex(Ex.Index))
1461
return make_error<GenericBinaryError>("invalid global export",
1462
object_error::parse_failed);
1463
Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
1464
uint64_t Offset = 0;
1465
if (isDefinedGlobalIndex(Ex.Index)) {
1466
auto Global = getDefinedGlobal(Ex.Index);
1467
if (!Global.InitExpr.Extended) {
1468
auto Inst = Global.InitExpr.Inst;
1469
if (Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1470
Offset = Inst.Value.Int32;
1471
} else if (Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1472
Offset = Inst.Value.Int64;
1473
}
1474
}
1475
}
1476
Info.DataRef = wasm::WasmDataReference{0, Offset, 0};
1477
break;
1478
}
1479
case wasm::WASM_EXTERNAL_TAG:
1480
if (!isValidTagIndex(Ex.Index))
1481
return make_error<GenericBinaryError>("invalid tag export",
1482
object_error::parse_failed);
1483
Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;
1484
Info.ElementIndex = Ex.Index;
1485
break;
1486
case wasm::WASM_EXTERNAL_MEMORY:
1487
break;
1488
case wasm::WASM_EXTERNAL_TABLE:
1489
Info.Kind = wasm::WASM_SYMBOL_TYPE_TABLE;
1490
Info.ElementIndex = Ex.Index;
1491
break;
1492
default:
1493
return make_error<GenericBinaryError>("unexpected export kind",
1494
object_error::parse_failed);
1495
}
1496
Exports.push_back(Ex);
1497
if (Ex.Kind != wasm::WASM_EXTERNAL_MEMORY) {
1498
Symbols.emplace_back(Info, GlobalType, TableType, Signature);
1499
LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
1500
}
1501
}
1502
if (Ctx.Ptr != Ctx.End)
1503
return make_error<GenericBinaryError>("export section ended prematurely",
1504
object_error::parse_failed);
1505
return Error::success();
1506
}
1507
1508
bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1509
return Index < NumImportedFunctions + Functions.size();
1510
}
1511
1512
bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1513
return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1514
}
1515
1516
bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1517
return Index < NumImportedGlobals + Globals.size();
1518
}
1519
1520
bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1521
return Index < NumImportedTables + Tables.size();
1522
}
1523
1524
bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1525
return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1526
}
1527
1528
bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1529
return Index >= NumImportedTables && isValidTableNumber(Index);
1530
}
1531
1532
bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
1533
return Index < NumImportedTags + Tags.size();
1534
}
1535
1536
bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
1537
return Index >= NumImportedTags && isValidTagIndex(Index);
1538
}
1539
1540
bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1541
return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1542
}
1543
1544
bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1545
return Index < Symbols.size() && Symbols[Index].isTypeTable();
1546
}
1547
1548
bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1549
return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1550
}
1551
1552
bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
1553
return Index < Symbols.size() && Symbols[Index].isTypeTag();
1554
}
1555
1556
bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1557
return Index < Symbols.size() && Symbols[Index].isTypeData();
1558
}
1559
1560
bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1561
return Index < Symbols.size() && Symbols[Index].isTypeSection();
1562
}
1563
1564
wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1565
assert(isDefinedFunctionIndex(Index));
1566
return Functions[Index - NumImportedFunctions];
1567
}
1568
1569
const wasm::WasmFunction &
1570
WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1571
assert(isDefinedFunctionIndex(Index));
1572
return Functions[Index - NumImportedFunctions];
1573
}
1574
1575
const wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) const {
1576
assert(isDefinedGlobalIndex(Index));
1577
return Globals[Index - NumImportedGlobals];
1578
}
1579
1580
wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
1581
assert(isDefinedTagIndex(Index));
1582
return Tags[Index - NumImportedTags];
1583
}
1584
1585
Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1586
StartFunction = readVaruint32(Ctx);
1587
if (!isValidFunctionIndex(StartFunction))
1588
return make_error<GenericBinaryError>("invalid start function",
1589
object_error::parse_failed);
1590
return Error::success();
1591
}
1592
1593
Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1594
CodeSection = Sections.size();
1595
uint32_t FunctionCount = readVaruint32(Ctx);
1596
if (FunctionCount != Functions.size()) {
1597
return make_error<GenericBinaryError>("invalid function count",
1598
object_error::parse_failed);
1599
}
1600
1601
for (uint32_t i = 0; i < FunctionCount; i++) {
1602
wasm::WasmFunction& Function = Functions[i];
1603
const uint8_t *FunctionStart = Ctx.Ptr;
1604
uint32_t Size = readVaruint32(Ctx);
1605
const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1606
1607
Function.CodeOffset = Ctx.Ptr - FunctionStart;
1608
Function.Index = NumImportedFunctions + i;
1609
Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1610
Function.Size = FunctionEnd - FunctionStart;
1611
1612
uint32_t NumLocalDecls = readVaruint32(Ctx);
1613
Function.Locals.reserve(NumLocalDecls);
1614
while (NumLocalDecls--) {
1615
wasm::WasmLocalDecl Decl;
1616
Decl.Count = readVaruint32(Ctx);
1617
Decl.Type = readUint8(Ctx);
1618
Function.Locals.push_back(Decl);
1619
}
1620
1621
uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1622
// Ensure that Function is within Ctx's buffer.
1623
if (Ctx.Ptr + BodySize > Ctx.End) {
1624
return make_error<GenericBinaryError>("Function extends beyond buffer",
1625
object_error::parse_failed);
1626
}
1627
Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1628
// This will be set later when reading in the linking metadata section.
1629
Function.Comdat = UINT32_MAX;
1630
Ctx.Ptr += BodySize;
1631
assert(Ctx.Ptr == FunctionEnd);
1632
}
1633
if (Ctx.Ptr != Ctx.End)
1634
return make_error<GenericBinaryError>("code section ended prematurely",
1635
object_error::parse_failed);
1636
return Error::success();
1637
}
1638
1639
Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1640
uint32_t Count = readVaruint32(Ctx);
1641
ElemSegments.reserve(Count);
1642
while (Count--) {
1643
wasm::WasmElemSegment Segment;
1644
Segment.Flags = readVaruint32(Ctx);
1645
1646
uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1647
wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1648
wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1649
if (Segment.Flags & ~SupportedFlags)
1650
return make_error<GenericBinaryError>(
1651
"Unsupported flags for element segment", object_error::parse_failed);
1652
1653
bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0;
1654
bool IsDeclarative =
1655
IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE);
1656
bool HasTableNumber =
1657
!IsPassive &&
1658
(Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);
1659
bool HasInitExprs =
1660
(Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
1661
bool HasElemKind =
1662
(Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) &&
1663
!HasInitExprs;
1664
1665
if (HasTableNumber)
1666
Segment.TableNumber = readVaruint32(Ctx);
1667
else
1668
Segment.TableNumber = 0;
1669
1670
if (!isValidTableNumber(Segment.TableNumber))
1671
return make_error<GenericBinaryError>("invalid TableNumber",
1672
object_error::parse_failed);
1673
1674
if (IsPassive || IsDeclarative) {
1675
Segment.Offset.Extended = false;
1676
Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1677
Segment.Offset.Inst.Value.Int32 = 0;
1678
} else {
1679
if (Error Err = readInitExpr(Segment.Offset, Ctx))
1680
return Err;
1681
}
1682
1683
if (HasElemKind) {
1684
auto ElemKind = readVaruint32(Ctx);
1685
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1686
Segment.ElemKind = parseValType(Ctx, ElemKind);
1687
if (Segment.ElemKind != wasm::ValType::FUNCREF &&
1688
Segment.ElemKind != wasm::ValType::EXTERNREF &&
1689
Segment.ElemKind != wasm::ValType::EXNREF &&
1690
Segment.ElemKind != wasm::ValType::OTHERREF) {
1691
return make_error<GenericBinaryError>("invalid elem type",
1692
object_error::parse_failed);
1693
}
1694
} else {
1695
if (ElemKind != 0)
1696
return make_error<GenericBinaryError>("invalid elem type",
1697
object_error::parse_failed);
1698
Segment.ElemKind = wasm::ValType::FUNCREF;
1699
}
1700
} else if (HasInitExprs) {
1701
auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
1702
Segment.ElemKind = ElemType;
1703
} else {
1704
Segment.ElemKind = wasm::ValType::FUNCREF;
1705
}
1706
1707
uint32_t NumElems = readVaruint32(Ctx);
1708
1709
if (HasInitExprs) {
1710
while (NumElems--) {
1711
wasm::WasmInitExpr Expr;
1712
if (Error Err = readInitExpr(Expr, Ctx))
1713
return Err;
1714
}
1715
} else {
1716
while (NumElems--) {
1717
Segment.Functions.push_back(readVaruint32(Ctx));
1718
}
1719
}
1720
ElemSegments.push_back(Segment);
1721
}
1722
if (Ctx.Ptr != Ctx.End)
1723
return make_error<GenericBinaryError>("elem section ended prematurely",
1724
object_error::parse_failed);
1725
return Error::success();
1726
}
1727
1728
Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1729
DataSection = Sections.size();
1730
uint32_t Count = readVaruint32(Ctx);
1731
if (DataCount && Count != *DataCount)
1732
return make_error<GenericBinaryError>(
1733
"number of data segments does not match DataCount section");
1734
DataSegments.reserve(Count);
1735
while (Count--) {
1736
WasmSegment Segment;
1737
Segment.Data.InitFlags = readVaruint32(Ctx);
1738
Segment.Data.MemoryIndex =
1739
(Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1740
? readVaruint32(Ctx)
1741
: 0;
1742
if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1743
if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1744
return Err;
1745
} else {
1746
Segment.Data.Offset.Extended = false;
1747
Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1748
Segment.Data.Offset.Inst.Value.Int32 = 0;
1749
}
1750
uint32_t Size = readVaruint32(Ctx);
1751
if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1752
return make_error<GenericBinaryError>("invalid segment size",
1753
object_error::parse_failed);
1754
Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1755
// The rest of these Data fields are set later, when reading in the linking
1756
// metadata section.
1757
Segment.Data.Alignment = 0;
1758
Segment.Data.LinkingFlags = 0;
1759
Segment.Data.Comdat = UINT32_MAX;
1760
Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1761
Ctx.Ptr += Size;
1762
DataSegments.push_back(Segment);
1763
}
1764
if (Ctx.Ptr != Ctx.End)
1765
return make_error<GenericBinaryError>("data section ended prematurely",
1766
object_error::parse_failed);
1767
return Error::success();
1768
}
1769
1770
Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1771
DataCount = readVaruint32(Ctx);
1772
return Error::success();
1773
}
1774
1775
const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1776
return Header;
1777
}
1778
1779
void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1780
1781
Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1782
uint32_t Result = SymbolRef::SF_None;
1783
const WasmSymbol &Sym = getWasmSymbol(Symb);
1784
1785
LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1786
if (Sym.isBindingWeak())
1787
Result |= SymbolRef::SF_Weak;
1788
if (!Sym.isBindingLocal())
1789
Result |= SymbolRef::SF_Global;
1790
if (Sym.isHidden())
1791
Result |= SymbolRef::SF_Hidden;
1792
if (!Sym.isDefined())
1793
Result |= SymbolRef::SF_Undefined;
1794
if (Sym.isTypeFunction())
1795
Result |= SymbolRef::SF_Executable;
1796
return Result;
1797
}
1798
1799
basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1800
DataRefImpl Ref;
1801
Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1802
Ref.d.b = 0; // Symbol index
1803
return BasicSymbolRef(Ref, this);
1804
}
1805
1806
basic_symbol_iterator WasmObjectFile::symbol_end() const {
1807
DataRefImpl Ref;
1808
Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1809
Ref.d.b = Symbols.size(); // Symbol index
1810
return BasicSymbolRef(Ref, this);
1811
}
1812
1813
const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1814
return Symbols[Symb.d.b];
1815
}
1816
1817
const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1818
return getWasmSymbol(Symb.getRawDataRefImpl());
1819
}
1820
1821
Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1822
return getWasmSymbol(Symb).Info.Name;
1823
}
1824
1825
Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1826
auto &Sym = getWasmSymbol(Symb);
1827
if (!Sym.isDefined())
1828
return 0;
1829
Expected<section_iterator> Sec = getSymbolSection(Symb);
1830
if (!Sec)
1831
return Sec.takeError();
1832
uint32_t SectionAddress = getSectionAddress(Sec.get()->getRawDataRefImpl());
1833
if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1834
isDefinedFunctionIndex(Sym.Info.ElementIndex)) {
1835
return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset +
1836
SectionAddress;
1837
}
1838
if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL &&
1839
isDefinedGlobalIndex(Sym.Info.ElementIndex)) {
1840
return getDefinedGlobal(Sym.Info.ElementIndex).Offset + SectionAddress;
1841
}
1842
1843
return getSymbolValue(Symb);
1844
}
1845
1846
uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1847
switch (Sym.Info.Kind) {
1848
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1849
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1850
case wasm::WASM_SYMBOL_TYPE_TAG:
1851
case wasm::WASM_SYMBOL_TYPE_TABLE:
1852
return Sym.Info.ElementIndex;
1853
case wasm::WASM_SYMBOL_TYPE_DATA: {
1854
// The value of a data symbol is the segment offset, plus the symbol
1855
// offset within the segment.
1856
uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1857
const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1858
if (Segment.Offset.Extended) {
1859
llvm_unreachable("extended init exprs not supported");
1860
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1861
return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1862
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1863
return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1864
} else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_GLOBAL_GET) {
1865
return Sym.Info.DataRef.Offset;
1866
} else {
1867
llvm_unreachable("unknown init expr opcode");
1868
}
1869
}
1870
case wasm::WASM_SYMBOL_TYPE_SECTION:
1871
return 0;
1872
}
1873
llvm_unreachable("invalid symbol type");
1874
}
1875
1876
uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1877
return getWasmSymbolValue(getWasmSymbol(Symb));
1878
}
1879
1880
uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1881
llvm_unreachable("not yet implemented");
1882
return 0;
1883
}
1884
1885
uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1886
llvm_unreachable("not yet implemented");
1887
return 0;
1888
}
1889
1890
Expected<SymbolRef::Type>
1891
WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1892
const WasmSymbol &Sym = getWasmSymbol(Symb);
1893
1894
switch (Sym.Info.Kind) {
1895
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1896
return SymbolRef::ST_Function;
1897
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1898
return SymbolRef::ST_Other;
1899
case wasm::WASM_SYMBOL_TYPE_DATA:
1900
return SymbolRef::ST_Data;
1901
case wasm::WASM_SYMBOL_TYPE_SECTION:
1902
return SymbolRef::ST_Debug;
1903
case wasm::WASM_SYMBOL_TYPE_TAG:
1904
return SymbolRef::ST_Other;
1905
case wasm::WASM_SYMBOL_TYPE_TABLE:
1906
return SymbolRef::ST_Other;
1907
}
1908
1909
llvm_unreachable("unknown WasmSymbol::SymbolType");
1910
return SymbolRef::ST_Other;
1911
}
1912
1913
Expected<section_iterator>
1914
WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1915
const WasmSymbol &Sym = getWasmSymbol(Symb);
1916
if (Sym.isUndefined())
1917
return section_end();
1918
1919
DataRefImpl Ref;
1920
Ref.d.a = getSymbolSectionIdImpl(Sym);
1921
return section_iterator(SectionRef(Ref, this));
1922
}
1923
1924
uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1925
const WasmSymbol &Sym = getWasmSymbol(Symb);
1926
return getSymbolSectionIdImpl(Sym);
1927
}
1928
1929
uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1930
switch (Sym.Info.Kind) {
1931
case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1932
return CodeSection;
1933
case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1934
return GlobalSection;
1935
case wasm::WASM_SYMBOL_TYPE_DATA:
1936
return DataSection;
1937
case wasm::WASM_SYMBOL_TYPE_SECTION:
1938
return Sym.Info.ElementIndex;
1939
case wasm::WASM_SYMBOL_TYPE_TAG:
1940
return TagSection;
1941
case wasm::WASM_SYMBOL_TYPE_TABLE:
1942
return TableSection;
1943
default:
1944
llvm_unreachable("unknown WasmSymbol::SymbolType");
1945
}
1946
}
1947
1948
uint32_t WasmObjectFile::getSymbolSize(SymbolRef Symb) const {
1949
const WasmSymbol &Sym = getWasmSymbol(Symb);
1950
if (!Sym.isDefined())
1951
return 0;
1952
if (Sym.isTypeGlobal())
1953
return getDefinedGlobal(Sym.Info.ElementIndex).Size;
1954
if (Sym.isTypeData())
1955
return Sym.Info.DataRef.Size;
1956
if (Sym.isTypeFunction())
1957
return functions()[Sym.Info.ElementIndex - getNumImportedFunctions()].Size;
1958
// Currently symbol size is only tracked for data segments and functions. In
1959
// principle we could also track size (e.g. binary size) for tables, globals
1960
// and element segments etc too.
1961
return 0;
1962
}
1963
1964
void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1965
1966
Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1967
const WasmSection &S = Sections[Sec.d.a];
1968
if (S.Type == wasm::WASM_SEC_CUSTOM)
1969
return S.Name;
1970
if (S.Type > wasm::WASM_SEC_LAST_KNOWN)
1971
return createStringError(object_error::invalid_section_index, "");
1972
return wasm::sectionTypeToString(S.Type);
1973
}
1974
1975
uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const {
1976
// For object files, use 0 for section addresses, and section offsets for
1977
// symbol addresses. For linked files, use file offsets.
1978
// See also getSymbolAddress.
1979
return isRelocatableObject() || isSharedObject() ? 0
1980
: Sections[Sec.d.a].Offset;
1981
}
1982
1983
uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1984
return Sec.d.a;
1985
}
1986
1987
uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1988
const WasmSection &S = Sections[Sec.d.a];
1989
return S.Content.size();
1990
}
1991
1992
Expected<ArrayRef<uint8_t>>
1993
WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1994
const WasmSection &S = Sections[Sec.d.a];
1995
// This will never fail since wasm sections can never be empty (user-sections
1996
// must have a name and non-user sections each have a defined structure).
1997
return S.Content;
1998
}
1999
2000
uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
2001
return 1;
2002
}
2003
2004
bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
2005
return false;
2006
}
2007
2008
bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
2009
return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
2010
}
2011
2012
bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
2013
return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
2014
}
2015
2016
bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
2017
2018
bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
2019
2020
relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
2021
DataRefImpl RelocRef;
2022
RelocRef.d.a = Ref.d.a;
2023
RelocRef.d.b = 0;
2024
return relocation_iterator(RelocationRef(RelocRef, this));
2025
}
2026
2027
relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
2028
const WasmSection &Sec = getWasmSection(Ref);
2029
DataRefImpl RelocRef;
2030
RelocRef.d.a = Ref.d.a;
2031
RelocRef.d.b = Sec.Relocations.size();
2032
return relocation_iterator(RelocationRef(RelocRef, this));
2033
}
2034
2035
void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
2036
2037
uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
2038
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2039
return Rel.Offset;
2040
}
2041
2042
symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
2043
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2044
if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
2045
return symbol_end();
2046
DataRefImpl Sym;
2047
Sym.d.a = 1;
2048
Sym.d.b = Rel.Index;
2049
return symbol_iterator(SymbolRef(Sym, this));
2050
}
2051
2052
uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
2053
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2054
return Rel.Type;
2055
}
2056
2057
void WasmObjectFile::getRelocationTypeName(
2058
DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
2059
const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2060
StringRef Res = "Unknown";
2061
2062
#define WASM_RELOC(name, value) \
2063
case wasm::name: \
2064
Res = #name; \
2065
break;
2066
2067
switch (Rel.Type) {
2068
#include "llvm/BinaryFormat/WasmRelocs.def"
2069
}
2070
2071
#undef WASM_RELOC
2072
2073
Result.append(Res.begin(), Res.end());
2074
}
2075
2076
section_iterator WasmObjectFile::section_begin() const {
2077
DataRefImpl Ref;
2078
Ref.d.a = 0;
2079
return section_iterator(SectionRef(Ref, this));
2080
}
2081
2082
section_iterator WasmObjectFile::section_end() const {
2083
DataRefImpl Ref;
2084
Ref.d.a = Sections.size();
2085
return section_iterator(SectionRef(Ref, this));
2086
}
2087
2088
uint8_t WasmObjectFile::getBytesInAddress() const {
2089
return HasMemory64 ? 8 : 4;
2090
}
2091
2092
StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
2093
2094
Triple::ArchType WasmObjectFile::getArch() const {
2095
return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
2096
}
2097
2098
Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {
2099
return SubtargetFeatures();
2100
}
2101
2102
bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
2103
2104
bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
2105
2106
const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
2107
assert(Ref.d.a < Sections.size());
2108
return Sections[Ref.d.a];
2109
}
2110
2111
const WasmSection &
2112
WasmObjectFile::getWasmSection(const SectionRef &Section) const {
2113
return getWasmSection(Section.getRawDataRefImpl());
2114
}
2115
2116
const wasm::WasmRelocation &
2117
WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
2118
return getWasmRelocation(Ref.getRawDataRefImpl());
2119
}
2120
2121
const wasm::WasmRelocation &
2122
WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
2123
assert(Ref.d.a < Sections.size());
2124
const WasmSection &Sec = Sections[Ref.d.a];
2125
assert(Ref.d.b < Sec.Relocations.size());
2126
return Sec.Relocations[Ref.d.b];
2127
}
2128
2129
int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
2130
StringRef CustomSectionName) {
2131
switch (ID) {
2132
case wasm::WASM_SEC_CUSTOM:
2133
return StringSwitch<unsigned>(CustomSectionName)
2134
.Case("dylink", WASM_SEC_ORDER_DYLINK)
2135
.Case("dylink.0", WASM_SEC_ORDER_DYLINK)
2136
.Case("linking", WASM_SEC_ORDER_LINKING)
2137
.StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
2138
.Case("name", WASM_SEC_ORDER_NAME)
2139
.Case("producers", WASM_SEC_ORDER_PRODUCERS)
2140
.Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
2141
.Default(WASM_SEC_ORDER_NONE);
2142
case wasm::WASM_SEC_TYPE:
2143
return WASM_SEC_ORDER_TYPE;
2144
case wasm::WASM_SEC_IMPORT:
2145
return WASM_SEC_ORDER_IMPORT;
2146
case wasm::WASM_SEC_FUNCTION:
2147
return WASM_SEC_ORDER_FUNCTION;
2148
case wasm::WASM_SEC_TABLE:
2149
return WASM_SEC_ORDER_TABLE;
2150
case wasm::WASM_SEC_MEMORY:
2151
return WASM_SEC_ORDER_MEMORY;
2152
case wasm::WASM_SEC_GLOBAL:
2153
return WASM_SEC_ORDER_GLOBAL;
2154
case wasm::WASM_SEC_EXPORT:
2155
return WASM_SEC_ORDER_EXPORT;
2156
case wasm::WASM_SEC_START:
2157
return WASM_SEC_ORDER_START;
2158
case wasm::WASM_SEC_ELEM:
2159
return WASM_SEC_ORDER_ELEM;
2160
case wasm::WASM_SEC_CODE:
2161
return WASM_SEC_ORDER_CODE;
2162
case wasm::WASM_SEC_DATA:
2163
return WASM_SEC_ORDER_DATA;
2164
case wasm::WASM_SEC_DATACOUNT:
2165
return WASM_SEC_ORDER_DATACOUNT;
2166
case wasm::WASM_SEC_TAG:
2167
return WASM_SEC_ORDER_TAG;
2168
default:
2169
return WASM_SEC_ORDER_NONE;
2170
}
2171
}
2172
2173
// Represents the edges in a directed graph where any node B reachable from node
2174
// A is not allowed to appear before A in the section ordering, but may appear
2175
// afterward.
2176
int WasmSectionOrderChecker::DisallowedPredecessors
2177
[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
2178
// WASM_SEC_ORDER_NONE
2179
{},
2180
// WASM_SEC_ORDER_TYPE
2181
{WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
2182
// WASM_SEC_ORDER_IMPORT
2183
{WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
2184
// WASM_SEC_ORDER_FUNCTION
2185
{WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
2186
// WASM_SEC_ORDER_TABLE
2187
{WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
2188
// WASM_SEC_ORDER_MEMORY
2189
{WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
2190
// WASM_SEC_ORDER_TAG
2191
{WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
2192
// WASM_SEC_ORDER_GLOBAL
2193
{WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
2194
// WASM_SEC_ORDER_EXPORT
2195
{WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
2196
// WASM_SEC_ORDER_START
2197
{WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
2198
// WASM_SEC_ORDER_ELEM
2199
{WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
2200
// WASM_SEC_ORDER_DATACOUNT
2201
{WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
2202
// WASM_SEC_ORDER_CODE
2203
{WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
2204
// WASM_SEC_ORDER_DATA
2205
{WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
2206
2207
// Custom Sections
2208
// WASM_SEC_ORDER_DYLINK
2209
{WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
2210
// WASM_SEC_ORDER_LINKING
2211
{WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
2212
// WASM_SEC_ORDER_RELOC (can be repeated)
2213
{},
2214
// WASM_SEC_ORDER_NAME
2215
{WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
2216
// WASM_SEC_ORDER_PRODUCERS
2217
{WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
2218
// WASM_SEC_ORDER_TARGET_FEATURES
2219
{WASM_SEC_ORDER_TARGET_FEATURES}};
2220
2221
bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
2222
StringRef CustomSectionName) {
2223
int Order = getSectionOrder(ID, CustomSectionName);
2224
if (Order == WASM_SEC_ORDER_NONE)
2225
return true;
2226
2227
// Disallowed predecessors we need to check for
2228
SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
2229
2230
// Keep track of completed checks to avoid repeating work
2231
bool Checked[WASM_NUM_SEC_ORDERS] = {};
2232
2233
int Curr = Order;
2234
while (true) {
2235
// Add new disallowed predecessors to work list
2236
for (size_t I = 0;; ++I) {
2237
int Next = DisallowedPredecessors[Curr][I];
2238
if (Next == WASM_SEC_ORDER_NONE)
2239
break;
2240
if (Checked[Next])
2241
continue;
2242
WorkList.push_back(Next);
2243
Checked[Next] = true;
2244
}
2245
2246
if (WorkList.empty())
2247
break;
2248
2249
// Consider next disallowed predecessor
2250
Curr = WorkList.pop_back_val();
2251
if (Seen[Curr])
2252
return false;
2253
}
2254
2255
// Have not seen any disallowed predecessors
2256
Seen[Order] = true;
2257
return true;
2258
}
2259
2260