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