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