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