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

source code of llvm/lib/Object/WasmObjectFile.cpp