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 case wasm::WASM_DYLINK_TARGET_ARCH:
510 DylinkInfo.TargetArch = readString(Ctx);
511 break;
512 default:
513 LLVM_DEBUG(dbgs() << "unknown dylink.0 sub-section: " << Type << "\n");
514 Ctx.Ptr += Size;
515 break;
516 }
517 if (Ctx.Ptr != Ctx.End) {
518 return make_error<GenericBinaryError>(
519 Args: "dylink.0 sub-section ended prematurely", Args: object_error::parse_failed);
520 }
521 }
522
523 if (Ctx.Ptr != Ctx.End)
524 return make_error<GenericBinaryError>(Args: "dylink.0 section ended prematurely",
525 Args: object_error::parse_failed);
526 return Error::success();
527}
528
529Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
530 llvm::DenseSet<uint64_t> SeenFunctions;
531 llvm::DenseSet<uint64_t> SeenGlobals;
532 llvm::DenseSet<uint64_t> SeenSegments;
533
534 // If we have linking section (symbol table) or if we are parsing a DSO
535 // then we don't use the name section for symbol information.
536 bool PopulateSymbolTable = !HasLinkingSection && !HasDylinkSection;
537
538 // If we are using the name section for symbol information then it will
539 // supersede any symbols created by the export section.
540 if (PopulateSymbolTable)
541 Symbols.clear();
542
543 while (Ctx.Ptr < Ctx.End) {
544 uint8_t Type = readUint8(Ctx);
545 uint32_t Size = readVaruint32(Ctx);
546 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
547
548 switch (Type) {
549 case wasm::WASM_NAMES_FUNCTION:
550 case wasm::WASM_NAMES_GLOBAL:
551 case wasm::WASM_NAMES_DATA_SEGMENT: {
552 uint32_t Count = readVaruint32(Ctx);
553 while (Count--) {
554 uint32_t Index = readVaruint32(Ctx);
555 StringRef Name = readString(Ctx);
556 wasm::NameType nameType = wasm::NameType::FUNCTION;
557 wasm::WasmSymbolInfo Info{.Name: Name,
558 /*Kind */ wasm::WASM_SYMBOL_TYPE_FUNCTION,
559 /* Flags */ 0,
560 /* ImportModule */ std::nullopt,
561 /* ImportName */ std::nullopt,
562 /* ExportName */ std::nullopt,
563 {/* ElementIndex */ Index}};
564 const wasm::WasmSignature *Signature = nullptr;
565 const wasm::WasmGlobalType *GlobalType = nullptr;
566 const wasm::WasmTableType *TableType = nullptr;
567 if (Type == wasm::WASM_NAMES_FUNCTION) {
568 if (!SeenFunctions.insert(V: Index).second)
569 return make_error<GenericBinaryError>(
570 Args: "function named more than once", Args: object_error::parse_failed);
571 if (!isValidFunctionIndex(Index) || Name.empty())
572 return make_error<GenericBinaryError>(Args: "invalid function name entry",
573 Args: object_error::parse_failed);
574
575 if (isDefinedFunctionIndex(Index)) {
576 wasm::WasmFunction &F = getDefinedFunction(Index);
577 F.DebugName = Name;
578 Signature = &Signatures[F.SigIndex];
579 if (F.ExportName) {
580 Info.ExportName = F.ExportName;
581 Info.Flags |= wasm::WASM_SYMBOL_BINDING_GLOBAL;
582 } else {
583 Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
584 }
585 } else {
586 Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
587 }
588 } else if (Type == wasm::WASM_NAMES_GLOBAL) {
589 if (!SeenGlobals.insert(V: Index).second)
590 return make_error<GenericBinaryError>(Args: "global named more than once",
591 Args: object_error::parse_failed);
592 if (!isValidGlobalIndex(Index) || Name.empty())
593 return make_error<GenericBinaryError>(Args: "invalid global name entry",
594 Args: object_error::parse_failed);
595 nameType = wasm::NameType::GLOBAL;
596 Info.Kind = wasm::WASM_SYMBOL_TYPE_GLOBAL;
597 if (isDefinedGlobalIndex(Index)) {
598 GlobalType = &getDefinedGlobal(Index).Type;
599 } else {
600 Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
601 }
602 } else {
603 if (!SeenSegments.insert(V: Index).second)
604 return make_error<GenericBinaryError>(
605 Args: "segment named more than once", Args: object_error::parse_failed);
606 if (Index >= DataSegments.size())
607 return make_error<GenericBinaryError>(Args: "invalid data segment name entry",
608 Args: object_error::parse_failed);
609 nameType = wasm::NameType::DATA_SEGMENT;
610 Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
611 Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
612 assert(Index < DataSegments.size());
613 Info.DataRef = wasm::WasmDataReference{
614 .Segment: Index, .Offset: 0, .Size: DataSegments[Index].Data.Content.size()};
615 }
616 DebugNames.push_back(x: wasm::WasmDebugName{.Type: nameType, .Index: Index, .Name: Name});
617 if (PopulateSymbolTable)
618 Symbols.emplace_back(args&: Info, args&: GlobalType, args&: TableType, args&: Signature);
619 }
620 break;
621 }
622 // Ignore local names for now
623 case wasm::WASM_NAMES_LOCAL:
624 default:
625 Ctx.Ptr += Size;
626 break;
627 }
628 if (Ctx.Ptr != SubSectionEnd)
629 return make_error<GenericBinaryError>(
630 Args: "name sub-section ended prematurely", Args: object_error::parse_failed);
631 }
632
633 if (Ctx.Ptr != Ctx.End)
634 return make_error<GenericBinaryError>(Args: "name section ended prematurely",
635 Args: object_error::parse_failed);
636 return Error::success();
637}
638
639Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
640 HasLinkingSection = true;
641
642 LinkingData.Version = readVaruint32(Ctx);
643 if (LinkingData.Version != wasm::WasmMetadataVersion) {
644 return make_error<GenericBinaryError>(
645 Args: "unexpected metadata version: " + Twine(LinkingData.Version) +
646 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
647 Args: object_error::parse_failed);
648 }
649
650 const uint8_t *OrigEnd = Ctx.End;
651 while (Ctx.Ptr < OrigEnd) {
652 Ctx.End = OrigEnd;
653 uint8_t Type = readUint8(Ctx);
654 uint32_t Size = readVaruint32(Ctx);
655 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
656 << "\n");
657 Ctx.End = Ctx.Ptr + Size;
658 switch (Type) {
659 case wasm::WASM_SYMBOL_TABLE:
660 if (Error Err = parseLinkingSectionSymtab(Ctx))
661 return Err;
662 break;
663 case wasm::WASM_SEGMENT_INFO: {
664 uint32_t Count = readVaruint32(Ctx);
665 if (Count > DataSegments.size())
666 return make_error<GenericBinaryError>(Args: "too many segment names",
667 Args: object_error::parse_failed);
668 for (uint32_t I = 0; I < Count; I++) {
669 DataSegments[I].Data.Name = readString(Ctx);
670 DataSegments[I].Data.Alignment = readVaruint32(Ctx);
671 if (DataSegments[I].Data.Alignment > 32)
672 return make_error<GenericBinaryError>(
673 Args: "invalid data segment alignment: `" + DataSegments[I].Data.Name +
674 "` (alignment: " + Twine(DataSegments[I].Data.Alignment) +
675 ")",
676 Args: object_error::parse_failed);
677 DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
678 }
679 break;
680 }
681 case wasm::WASM_INIT_FUNCS: {
682 uint32_t Count = readVaruint32(Ctx);
683 LinkingData.InitFunctions.reserve(n: Count);
684 for (uint32_t I = 0; I < Count; I++) {
685 wasm::WasmInitFunc Init;
686 Init.Priority = readVaruint32(Ctx);
687 Init.Symbol = readVaruint32(Ctx);
688 if (!isValidFunctionSymbol(Index: Init.Symbol))
689 return make_error<GenericBinaryError>(Args: "invalid function symbol: " +
690 Twine(Init.Symbol),
691 Args: object_error::parse_failed);
692 LinkingData.InitFunctions.emplace_back(args&: Init);
693 }
694 break;
695 }
696 case wasm::WASM_COMDAT_INFO:
697 if (Error Err = parseLinkingSectionComdat(Ctx))
698 return Err;
699 break;
700 case wasm::WASM_TARGET_ARCH:
701 LinkingData.TargetArch = readString(Ctx);
702 break;
703 default:
704 Ctx.Ptr += Size;
705 break;
706 }
707 if (Ctx.Ptr != Ctx.End)
708 return make_error<GenericBinaryError>(
709 Args: "linking sub-section ended prematurely", Args: object_error::parse_failed);
710 }
711 if (Ctx.Ptr != OrigEnd)
712 return make_error<GenericBinaryError>(Args: "linking section ended prematurely",
713 Args: object_error::parse_failed);
714 return Error::success();
715}
716
717Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
718 uint32_t Count = readVaruint32(Ctx);
719 // Clear out any symbol information that was derived from the exports
720 // section.
721 Symbols.clear();
722 Symbols.reserve(n: Count);
723 StringSet<> SymbolNames;
724
725 std::vector<wasm::WasmImport *> ImportedGlobals;
726 std::vector<wasm::WasmImport *> ImportedFunctions;
727 std::vector<wasm::WasmImport *> ImportedTags;
728 std::vector<wasm::WasmImport *> ImportedTables;
729 ImportedGlobals.reserve(n: Imports.size());
730 ImportedFunctions.reserve(n: Imports.size());
731 ImportedTags.reserve(n: Imports.size());
732 ImportedTables.reserve(n: Imports.size());
733 for (auto &I : Imports) {
734 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
735 ImportedFunctions.emplace_back(args: &I);
736 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
737 ImportedGlobals.emplace_back(args: &I);
738 else if (I.Kind == wasm::WASM_EXTERNAL_TAG)
739 ImportedTags.emplace_back(args: &I);
740 else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
741 ImportedTables.emplace_back(args: &I);
742 }
743
744 while (Count--) {
745 wasm::WasmSymbolInfo Info;
746 const wasm::WasmSignature *Signature = nullptr;
747 const wasm::WasmGlobalType *GlobalType = nullptr;
748 const wasm::WasmTableType *TableType = nullptr;
749
750 Info.Kind = readUint8(Ctx);
751 Info.Flags = readVaruint32(Ctx);
752 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
753
754 switch (Info.Kind) {
755 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
756 Info.ElementIndex = readVaruint32(Ctx);
757 if (!isValidFunctionIndex(Index: Info.ElementIndex) ||
758 IsDefined != isDefinedFunctionIndex(Index: Info.ElementIndex))
759 return make_error<GenericBinaryError>(Args: "invalid function symbol index",
760 Args: object_error::parse_failed);
761 if (IsDefined) {
762 Info.Name = readString(Ctx);
763 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
764 wasm::WasmFunction &Function = Functions[FuncIndex];
765 Signature = &Signatures[Function.SigIndex];
766 if (Function.SymbolName.empty())
767 Function.SymbolName = Info.Name;
768 } else {
769 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
770 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
771 Info.Name = readString(Ctx);
772 Info.ImportName = Import.Field;
773 } else {
774 Info.Name = Import.Field;
775 }
776 Signature = &Signatures[Import.SigIndex];
777 Info.ImportModule = Import.Module;
778 }
779 break;
780
781 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
782 Info.ElementIndex = readVaruint32(Ctx);
783 if (!isValidGlobalIndex(Index: Info.ElementIndex) ||
784 IsDefined != isDefinedGlobalIndex(Index: Info.ElementIndex))
785 return make_error<GenericBinaryError>(Args: "invalid global symbol index",
786 Args: object_error::parse_failed);
787 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
788 wasm::WASM_SYMBOL_BINDING_WEAK)
789 return make_error<GenericBinaryError>(Args: "undefined weak global symbol",
790 Args: object_error::parse_failed);
791 if (IsDefined) {
792 Info.Name = readString(Ctx);
793 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
794 wasm::WasmGlobal &Global = Globals[GlobalIndex];
795 GlobalType = &Global.Type;
796 if (Global.SymbolName.empty())
797 Global.SymbolName = Info.Name;
798 } else {
799 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
800 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
801 Info.Name = readString(Ctx);
802 Info.ImportName = Import.Field;
803 } else {
804 Info.Name = Import.Field;
805 }
806 GlobalType = &Import.Global;
807 Info.ImportModule = Import.Module;
808 }
809 break;
810
811 case wasm::WASM_SYMBOL_TYPE_TABLE:
812 Info.ElementIndex = readVaruint32(Ctx);
813 if (!isValidTableNumber(Index: Info.ElementIndex) ||
814 IsDefined != isDefinedTableNumber(Index: Info.ElementIndex))
815 return make_error<GenericBinaryError>(Args: "invalid table symbol index",
816 Args: object_error::parse_failed);
817 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
818 wasm::WASM_SYMBOL_BINDING_WEAK)
819 return make_error<GenericBinaryError>(Args: "undefined weak table symbol",
820 Args: object_error::parse_failed);
821 if (IsDefined) {
822 Info.Name = readString(Ctx);
823 unsigned TableNumber = Info.ElementIndex - NumImportedTables;
824 wasm::WasmTable &Table = Tables[TableNumber];
825 TableType = &Table.Type;
826 if (Table.SymbolName.empty())
827 Table.SymbolName = Info.Name;
828 } else {
829 wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
830 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
831 Info.Name = readString(Ctx);
832 Info.ImportName = Import.Field;
833 } else {
834 Info.Name = Import.Field;
835 }
836 TableType = &Import.Table;
837 Info.ImportModule = Import.Module;
838 }
839 break;
840
841 case wasm::WASM_SYMBOL_TYPE_DATA:
842 Info.Name = readString(Ctx);
843 if (IsDefined) {
844 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
845 wasm::WASM_SYMBOL_BINDING_COMMON) {
846 if (Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE)
847 return make_error<GenericBinaryError>(
848 Args: "common symbols cannot be absolute: " + Info.Name,
849 Args: object_error::parse_failed);
850 auto Size = readVaruint64(Ctx);
851 auto Alignment = readUint8(Ctx);
852 if (Alignment > 32)
853 return make_error<GenericBinaryError>(
854 Args: "invalid common symbol alignment: `" + Info.Name +
855 "` (alignment: " + Twine(unsigned(Alignment)) + ")",
856 Args: object_error::parse_failed);
857 Info.CommonRef = wasm::WasmCommonReference{.Size: Size, .Alignment: Alignment};
858 } else {
859 auto Index = readVaruint32(Ctx);
860 auto Offset = readVaruint64(Ctx);
861 auto Size = readVaruint64(Ctx);
862 if (!(Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE)) {
863 if (Index >= DataSegments.size())
864 return make_error<GenericBinaryError>(
865 Args: "invalid data segment index: " + Twine(Index),
866 Args: object_error::parse_failed);
867 size_t SegmentSize = DataSegments[Index].Data.Content.size();
868 if (Offset > SegmentSize)
869 return make_error<GenericBinaryError>(
870 Args: "invalid data symbol offset: `" + Info.Name +
871 "` (offset: " + Twine(Offset) +
872 " segment size: " + Twine(SegmentSize) + ")",
873 Args: object_error::parse_failed);
874 }
875 Info.DataRef = wasm::WasmDataReference{.Segment: Index, .Offset: Offset, .Size: Size};
876 }
877 }
878 break;
879
880 case wasm::WASM_SYMBOL_TYPE_SECTION: {
881 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
882 wasm::WASM_SYMBOL_BINDING_LOCAL)
883 return make_error<GenericBinaryError>(
884 Args: "section symbols must have local binding",
885 Args: object_error::parse_failed);
886 Info.ElementIndex = readVaruint32(Ctx);
887 // Use somewhat unique section name as symbol name.
888 StringRef SectionName = Sections[Info.ElementIndex].Name;
889 Info.Name = SectionName;
890 break;
891 }
892
893 case wasm::WASM_SYMBOL_TYPE_TAG: {
894 Info.ElementIndex = readVaruint32(Ctx);
895 if (!isValidTagIndex(Index: Info.ElementIndex) ||
896 IsDefined != isDefinedTagIndex(Index: Info.ElementIndex))
897 return make_error<GenericBinaryError>(Args: "invalid tag symbol index",
898 Args: object_error::parse_failed);
899 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
900 wasm::WASM_SYMBOL_BINDING_WEAK)
901 return make_error<GenericBinaryError>(Args: "undefined weak global symbol",
902 Args: object_error::parse_failed);
903 if (IsDefined) {
904 Info.Name = readString(Ctx);
905 unsigned TagIndex = Info.ElementIndex - NumImportedTags;
906 wasm::WasmTag &Tag = Tags[TagIndex];
907 Signature = &Signatures[Tag.SigIndex];
908 if (Tag.SymbolName.empty())
909 Tag.SymbolName = Info.Name;
910
911 } else {
912 wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
913 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
914 Info.Name = readString(Ctx);
915 Info.ImportName = Import.Field;
916 } else {
917 Info.Name = Import.Field;
918 }
919 Signature = &Signatures[Import.SigIndex];
920 Info.ImportModule = Import.Module;
921 }
922 break;
923 }
924
925 default:
926 return make_error<GenericBinaryError>(Args: "invalid symbol type: " +
927 Twine(unsigned(Info.Kind)),
928 Args: object_error::parse_failed);
929 }
930
931 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
932 wasm::WASM_SYMBOL_BINDING_LOCAL &&
933 !SymbolNames.insert(key: Info.Name).second)
934 return make_error<GenericBinaryError>(Args: "duplicate symbol name " +
935 Twine(Info.Name),
936 Args: object_error::parse_failed);
937 Symbols.emplace_back(args&: Info, args&: GlobalType, args&: TableType, args&: Signature);
938 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
939 }
940
941 return Error::success();
942}
943
944Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
945 uint32_t ComdatCount = readVaruint32(Ctx);
946 StringSet<> ComdatSet;
947 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
948 StringRef Name = readString(Ctx);
949 if (Name.empty() || !ComdatSet.insert(key: Name).second)
950 return make_error<GenericBinaryError>(Args: "bad/duplicate COMDAT name " +
951 Twine(Name),
952 Args: object_error::parse_failed);
953 LinkingData.Comdats.emplace_back(args&: Name);
954 uint32_t Flags = readVaruint32(Ctx);
955 if (Flags != 0)
956 return make_error<GenericBinaryError>(Args: "unsupported COMDAT flags",
957 Args: object_error::parse_failed);
958
959 uint32_t EntryCount = readVaruint32(Ctx);
960 while (EntryCount--) {
961 unsigned Kind = readVaruint32(Ctx);
962 unsigned Index = readVaruint32(Ctx);
963 switch (Kind) {
964 default:
965 return make_error<GenericBinaryError>(Args: "invalid COMDAT entry type",
966 Args: object_error::parse_failed);
967 case wasm::WASM_COMDAT_DATA:
968 if (Index >= DataSegments.size())
969 return make_error<GenericBinaryError>(
970 Args: "COMDAT data index out of range", Args: object_error::parse_failed);
971 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
972 return make_error<GenericBinaryError>(Args: "data segment in two COMDATs",
973 Args: object_error::parse_failed);
974 DataSegments[Index].Data.Comdat = ComdatIndex;
975 break;
976 case wasm::WASM_COMDAT_FUNCTION:
977 if (!isDefinedFunctionIndex(Index))
978 return make_error<GenericBinaryError>(
979 Args: "COMDAT function index out of range", Args: object_error::parse_failed);
980 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
981 return make_error<GenericBinaryError>(Args: "function in two COMDATs",
982 Args: object_error::parse_failed);
983 getDefinedFunction(Index).Comdat = ComdatIndex;
984 break;
985 case wasm::WASM_COMDAT_SECTION:
986 if (Index >= Sections.size())
987 return make_error<GenericBinaryError>(
988 Args: "COMDAT section index out of range", Args: object_error::parse_failed);
989 if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
990 return make_error<GenericBinaryError>(
991 Args: "non-custom section in a COMDAT", Args: object_error::parse_failed);
992 Sections[Index].Comdat = ComdatIndex;
993 break;
994 }
995 }
996 }
997 return Error::success();
998}
999
1000Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
1001 llvm::SmallSet<StringRef, 3> FieldsSeen;
1002 uint32_t Fields = readVaruint32(Ctx);
1003 for (size_t I = 0; I < Fields; ++I) {
1004 StringRef FieldName = readString(Ctx);
1005 if (!FieldsSeen.insert(V: FieldName).second)
1006 return make_error<GenericBinaryError>(
1007 Args: "producers section does not have unique fields",
1008 Args: object_error::parse_failed);
1009 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
1010 if (FieldName == "language") {
1011 ProducerVec = &ProducerInfo.Languages;
1012 } else if (FieldName == "processed-by") {
1013 ProducerVec = &ProducerInfo.Tools;
1014 } else if (FieldName == "sdk") {
1015 ProducerVec = &ProducerInfo.SDKs;
1016 } else {
1017 return make_error<GenericBinaryError>(
1018 Args: "producers section field is not named one of language, processed-by, "
1019 "or sdk",
1020 Args: object_error::parse_failed);
1021 }
1022 uint32_t ValueCount = readVaruint32(Ctx);
1023 llvm::SmallSet<StringRef, 8> ProducersSeen;
1024 for (size_t J = 0; J < ValueCount; ++J) {
1025 StringRef Name = readString(Ctx);
1026 StringRef Version = readString(Ctx);
1027 if (!ProducersSeen.insert(V: Name).second) {
1028 return make_error<GenericBinaryError>(
1029 Args: "producers section contains repeated producer",
1030 Args: object_error::parse_failed);
1031 }
1032 ProducerVec->emplace_back(args: std::string(Name), args: std::string(Version));
1033 }
1034 }
1035 if (Ctx.Ptr != Ctx.End)
1036 return make_error<GenericBinaryError>(Args: "producers section ended prematurely",
1037 Args: object_error::parse_failed);
1038 return Error::success();
1039}
1040
1041Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
1042 llvm::SmallSet<std::string, 8> FeaturesSeen;
1043 uint32_t FeatureCount = readVaruint32(Ctx);
1044 for (size_t I = 0; I < FeatureCount; ++I) {
1045 wasm::WasmFeatureEntry Feature;
1046 Feature.Prefix = readUint8(Ctx);
1047 switch (Feature.Prefix) {
1048 case wasm::WASM_FEATURE_PREFIX_USED:
1049 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
1050 break;
1051 default:
1052 return make_error<GenericBinaryError>(Args: "unknown feature policy prefix",
1053 Args: object_error::parse_failed);
1054 }
1055 Feature.Name = std::string(readString(Ctx));
1056 if (!FeaturesSeen.insert(V: Feature.Name).second)
1057 return make_error<GenericBinaryError>(
1058 Args: "target features section contains repeated feature \"" +
1059 Feature.Name + "\"",
1060 Args: object_error::parse_failed);
1061 TargetFeatures.push_back(x: Feature);
1062 }
1063 if (Ctx.Ptr != Ctx.End)
1064 return make_error<GenericBinaryError>(
1065 Args: "target features section ended prematurely",
1066 Args: object_error::parse_failed);
1067 return Error::success();
1068}
1069
1070Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
1071 uint32_t SectionIndex = readVaruint32(Ctx);
1072 if (SectionIndex >= Sections.size())
1073 return make_error<GenericBinaryError>(Args: "invalid section index",
1074 Args: object_error::parse_failed);
1075 WasmSection &Section = Sections[SectionIndex];
1076 uint32_t RelocCount = readVaruint32(Ctx);
1077 uint32_t EndOffset = Section.Content.size();
1078 uint32_t PreviousOffset = 0;
1079 while (RelocCount--) {
1080 wasm::WasmRelocation Reloc = {};
1081 uint32_t type = readVaruint32(Ctx);
1082 Reloc.Type = type;
1083 Reloc.Offset = readVaruint32(Ctx);
1084 if (Reloc.Offset < PreviousOffset)
1085 return make_error<GenericBinaryError>(Args: "relocations not in offset order",
1086 Args: object_error::parse_failed);
1087
1088 auto badReloc = [&](StringRef msg) {
1089 if (Reloc.Index >= Symbols.size())
1090 return make_error<GenericBinaryError>(
1091 Args: msg + ": index " + Twine(Reloc.Index) + " out of range",
1092 Args: object_error::parse_failed);
1093 return make_error<GenericBinaryError>(
1094 Args: msg + ": " + Twine(Symbols[Reloc.Index].Info.Name),
1095 Args: object_error::parse_failed);
1096 };
1097
1098 PreviousOffset = Reloc.Offset;
1099 Reloc.Index = readVaruint32(Ctx);
1100 switch (type) {
1101 case wasm::R_WASM_FUNCTION_INDEX_LEB:
1102 case wasm::R_WASM_FUNCTION_INDEX_I32:
1103 case wasm::R_WASM_TABLE_INDEX_SLEB:
1104 case wasm::R_WASM_TABLE_INDEX_SLEB64:
1105 case wasm::R_WASM_TABLE_INDEX_I32:
1106 case wasm::R_WASM_TABLE_INDEX_I64:
1107 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
1108 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
1109 if (!isValidFunctionSymbol(Index: Reloc.Index))
1110 return badReloc("invalid function relocation");
1111 break;
1112 case wasm::R_WASM_TABLE_NUMBER_LEB:
1113 if (!isValidTableSymbol(Index: Reloc.Index))
1114 return badReloc("invalid table relocation");
1115 break;
1116 case wasm::R_WASM_TYPE_INDEX_LEB:
1117 if (Reloc.Index >= Signatures.size())
1118 return badReloc("invalid relocation type index");
1119 break;
1120 case wasm::R_WASM_GLOBAL_INDEX_LEB:
1121 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
1122 // symbols to refer to their GOT entries.
1123 if (!isValidGlobalSymbol(Index: Reloc.Index) &&
1124 !isValidDataSymbol(Index: Reloc.Index) &&
1125 !isValidFunctionSymbol(Index: Reloc.Index))
1126 return badReloc("invalid global relocation");
1127 break;
1128 case wasm::R_WASM_GLOBAL_INDEX_I32:
1129 if (!isValidGlobalSymbol(Index: Reloc.Index))
1130 return badReloc("invalid global relocation");
1131 break;
1132 case wasm::R_WASM_TAG_INDEX_LEB:
1133 if (!isValidTagSymbol(Index: Reloc.Index))
1134 return badReloc("invalid tag relocation");
1135 break;
1136 case wasm::R_WASM_MEMORY_ADDR_LEB:
1137 case wasm::R_WASM_MEMORY_ADDR_SLEB:
1138 case wasm::R_WASM_MEMORY_ADDR_I32:
1139 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
1140 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
1141 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
1142 if (!isValidDataSymbol(Index: Reloc.Index))
1143 return badReloc("invalid data relocation");
1144 Reloc.Addend = readVarint32(Ctx);
1145 break;
1146 case wasm::R_WASM_MEMORY_ADDR_LEB64:
1147 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
1148 case wasm::R_WASM_MEMORY_ADDR_I64:
1149 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
1150 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
1151 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I64:
1152 if (!isValidDataSymbol(Index: Reloc.Index))
1153 return badReloc("invalid data relocation");
1154 Reloc.Addend = readVarint64(Ctx);
1155 break;
1156 case wasm::R_WASM_FUNCTION_OFFSET_I32:
1157 if (!isValidFunctionSymbol(Index: Reloc.Index))
1158 return badReloc("invalid function relocation");
1159 Reloc.Addend = readVarint32(Ctx);
1160 break;
1161 case wasm::R_WASM_FUNCTION_OFFSET_I64:
1162 if (!isValidFunctionSymbol(Index: Reloc.Index))
1163 return badReloc("invalid function relocation");
1164 Reloc.Addend = readVarint64(Ctx);
1165 break;
1166 case wasm::R_WASM_SECTION_OFFSET_I32:
1167 if (!isValidSectionSymbol(Index: Reloc.Index))
1168 return badReloc("invalid section relocation");
1169 Reloc.Addend = readVarint32(Ctx);
1170 break;
1171 default:
1172 return make_error<GenericBinaryError>(Args: "invalid relocation type: " +
1173 Twine(type),
1174 Args: object_error::parse_failed);
1175 }
1176
1177 // Relocations must fit inside the section, and must appear in order. They
1178 // also shouldn't overlap a function/element boundary, but we don't bother
1179 // to check that.
1180 uint64_t Size = 5;
1181 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
1182 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
1183 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
1184 Size = 10;
1185 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
1186 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
1187 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
1188 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
1189 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
1190 Reloc.Type == wasm::R_WASM_FUNCTION_INDEX_I32 ||
1191 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
1192 Size = 4;
1193 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
1194 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
1195 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64 ||
1196 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I64)
1197 Size = 8;
1198 if (Reloc.Offset + Size > EndOffset)
1199 return make_error<GenericBinaryError>(Args: "invalid relocation offset",
1200 Args: object_error::parse_failed);
1201
1202 Section.Relocations.push_back(x: Reloc);
1203 }
1204 if (Ctx.Ptr != Ctx.End)
1205 return make_error<GenericBinaryError>(Args: "reloc section ended prematurely",
1206 Args: object_error::parse_failed);
1207 return Error::success();
1208}
1209
1210Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
1211 if (Sec.Name == "dylink") {
1212 if (Error Err = parseDylinkSection(Ctx))
1213 return Err;
1214 } else if (Sec.Name == "dylink.0") {
1215 if (Error Err = parseDylink0Section(Ctx))
1216 return Err;
1217 } else if (Sec.Name == "name") {
1218 if (Error Err = parseNameSection(Ctx))
1219 return Err;
1220 } else if (Sec.Name == "linking") {
1221 if (Error Err = parseLinkingSection(Ctx))
1222 return Err;
1223 } else if (Sec.Name == "producers") {
1224 if (Error Err = parseProducersSection(Ctx))
1225 return Err;
1226 } else if (Sec.Name == "target_features") {
1227 if (Error Err = parseTargetFeaturesSection(Ctx))
1228 return Err;
1229 } else if (Sec.Name.starts_with(Prefix: "reloc.")) {
1230 if (Error Err = parseRelocSection(Name: Sec.Name, Ctx))
1231 return Err;
1232 }
1233 return Error::success();
1234}
1235
1236Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1237 auto parseFieldDef = [&]() {
1238 uint32_t TypeCode = readVaruint32((Ctx));
1239 /* Discard StorageType */ parseValType(Ctx, Code: TypeCode);
1240 /* Discard Mutability */ readVaruint32(Ctx);
1241 };
1242
1243 uint32_t Count = readVaruint32(Ctx);
1244 Signatures.reserve(n: Count);
1245 while (Count--) {
1246 wasm::WasmSignature Sig;
1247 uint8_t Form = readUint8(Ctx);
1248 if (Form == wasm::WASM_TYPE_REC) {
1249 // Rec groups expand the type index space (beyond what was declared at
1250 // the top of the section, and also consume one element in that space.
1251 uint32_t RecSize = readVaruint32(Ctx);
1252 if (RecSize == 0)
1253 return make_error<GenericBinaryError>(Args: "Rec group size cannot be 0",
1254 Args: object_error::parse_failed);
1255 Signatures.reserve(n: Signatures.size() + RecSize);
1256 Count += RecSize;
1257 Sig.Kind = wasm::WasmSignature::Placeholder;
1258 Signatures.push_back(x: std::move(Sig));
1259 HasUnmodeledTypes = true;
1260 continue;
1261 }
1262 if (Form != wasm::WASM_TYPE_FUNC) {
1263 // Currently LLVM only models function types, and not other composite
1264 // types. Here we parse the type declarations just enough to skip past
1265 // them in the binary.
1266 if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
1267 uint32_t Supers = readVaruint32(Ctx);
1268 if (Supers > 0) {
1269 if (Supers != 1)
1270 return make_error<GenericBinaryError>(
1271 Args: "Invalid number of supertypes", Args: object_error::parse_failed);
1272 /* Discard SuperIndex */ readVaruint32(Ctx);
1273 }
1274 Form = readVaruint32(Ctx);
1275 }
1276 if (Form == wasm::WASM_TYPE_STRUCT) {
1277 uint32_t FieldCount = readVaruint32(Ctx);
1278 while (FieldCount--) {
1279 parseFieldDef();
1280 }
1281 } else if (Form == wasm::WASM_TYPE_ARRAY) {
1282 parseFieldDef();
1283 } else {
1284 return make_error<GenericBinaryError>(Args: "bad form",
1285 Args: object_error::parse_failed);
1286 }
1287 Sig.Kind = wasm::WasmSignature::Placeholder;
1288 Signatures.push_back(x: std::move(Sig));
1289 HasUnmodeledTypes = true;
1290 continue;
1291 }
1292
1293 uint32_t ParamCount = readVaruint32(Ctx);
1294 Sig.Params.reserve(N: ParamCount);
1295 while (ParamCount--) {
1296 uint32_t ParamType = readUint8(Ctx);
1297 Sig.Params.push_back(Elt: parseValType(Ctx, Code: ParamType));
1298 }
1299 uint32_t ReturnCount = readVaruint32(Ctx);
1300 while (ReturnCount--) {
1301 uint32_t ReturnType = readUint8(Ctx);
1302 Sig.Returns.push_back(Elt: parseValType(Ctx, Code: ReturnType));
1303 }
1304
1305 Signatures.push_back(x: std::move(Sig));
1306 }
1307 if (Ctx.Ptr != Ctx.End)
1308 return make_error<GenericBinaryError>(Args: "type section ended prematurely",
1309 Args: object_error::parse_failed);
1310 return Error::success();
1311}
1312
1313Error WasmObjectFile::parseImport(ReadContext &Ctx, wasm::WasmImport &Im) {
1314 switch (Im.Kind) {
1315 case wasm::WASM_EXTERNAL_FUNCTION:
1316 NumImportedFunctions++;
1317 Im.SigIndex = readVaruint32(Ctx);
1318 if (Im.SigIndex >= Signatures.size())
1319 return make_error<GenericBinaryError>(Args: "invalid function type",
1320 Args: object_error::parse_failed);
1321 break;
1322 case wasm::WASM_EXTERNAL_GLOBAL:
1323 NumImportedGlobals++;
1324 Im.Global.Type = readUint8(Ctx);
1325 Im.Global.Mutable = readVaruint1(Ctx);
1326 break;
1327 case wasm::WASM_EXTERNAL_MEMORY:
1328 Im.Memory = readLimits(Ctx);
1329 if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1330 HasMemory64 = true;
1331 break;
1332 case wasm::WASM_EXTERNAL_TABLE: {
1333 Im.Table = readTableType(Ctx);
1334 NumImportedTables++;
1335 auto ElemType = Im.Table.ElemType;
1336 if (ElemType != wasm::ValType::FUNCREF &&
1337 ElemType != wasm::ValType::EXTERNREF &&
1338 ElemType != wasm::ValType::EXNREF &&
1339 ElemType != wasm::ValType::OTHERREF)
1340 return make_error<GenericBinaryError>(Args: "invalid table element type",
1341 Args: object_error::parse_failed);
1342 break;
1343 }
1344 case wasm::WASM_EXTERNAL_TAG:
1345 NumImportedTags++;
1346 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1347 return make_error<GenericBinaryError>(Args: "invalid attribute",
1348 Args: object_error::parse_failed);
1349 Im.SigIndex = readVaruint32(Ctx);
1350 if (Im.SigIndex >= Signatures.size())
1351 return make_error<GenericBinaryError>(Args: "invalid tag type",
1352 Args: object_error::parse_failed);
1353 break;
1354 default:
1355 return make_error<GenericBinaryError>(Args: "unexpected import kind: " +
1356 Twine(unsigned(Im.Kind)),
1357 Args: object_error::parse_failed);
1358 }
1359 Imports.push_back(x: Im);
1360 return Error::success();
1361}
1362
1363Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1364 uint32_t Count = readVaruint32(Ctx);
1365 Imports.reserve(n: Count);
1366 uint32_t I = 0;
1367 while (I < Count) {
1368 wasm::WasmImport Im;
1369 Im.Module = readString(Ctx);
1370 Im.Field = readString(Ctx);
1371 Im.Kind = readUint8(Ctx);
1372 // 0x7E/0x7F along with an empty Field signals a block of compact imports.
1373 if (Im.Kind == 0x7E && Im.Field == "") {
1374 return make_error<GenericBinaryError>(
1375 Args: "compact import format (0x7E) is not yet supported",
1376 Args: object_error::parse_failed);
1377 } else if (Im.Kind == 0x7F && Im.Field == "") {
1378 uint32_t NumCompactImports = readVaruint32(Ctx);
1379 while (NumCompactImports--) {
1380 Im.Field = readString(Ctx);
1381 Im.Kind = readUint8(Ctx);
1382 Error rtn = parseImport(Ctx, Im);
1383 if (rtn)
1384 return rtn;
1385 I++;
1386 }
1387 } else {
1388 Error rtn = parseImport(Ctx, Im);
1389 if (rtn)
1390 return rtn;
1391 I++;
1392 }
1393 }
1394 if (Ctx.Ptr != Ctx.End)
1395 return make_error<GenericBinaryError>(Args: "import section ended prematurely",
1396 Args: object_error::parse_failed);
1397 return Error::success();
1398}
1399
1400Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1401 uint32_t Count = readVaruint32(Ctx);
1402 Functions.reserve(n: Count);
1403 uint32_t NumTypes = Signatures.size();
1404 while (Count--) {
1405 uint32_t Type = readVaruint32(Ctx);
1406 if (Type >= NumTypes)
1407 return make_error<GenericBinaryError>(Args: "invalid function type",
1408 Args: object_error::parse_failed);
1409 wasm::WasmFunction F;
1410 F.SigIndex = Type;
1411 Functions.push_back(x: F);
1412 }
1413 if (Ctx.Ptr != Ctx.End)
1414 return make_error<GenericBinaryError>(Args: "function section ended prematurely",
1415 Args: object_error::parse_failed);
1416 return Error::success();
1417}
1418
1419Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1420 TableSection = Sections.size();
1421 uint32_t Count = readVaruint32(Ctx);
1422 Tables.reserve(n: Count);
1423 while (Count--) {
1424 wasm::WasmTable T;
1425 T.Type = readTableType(Ctx);
1426 T.Index = NumImportedTables + Tables.size();
1427 Tables.push_back(x: T);
1428 auto ElemType = Tables.back().Type.ElemType;
1429 if (ElemType != wasm::ValType::FUNCREF &&
1430 ElemType != wasm::ValType::EXTERNREF &&
1431 ElemType != wasm::ValType::EXNREF &&
1432 ElemType != wasm::ValType::OTHERREF) {
1433 return make_error<GenericBinaryError>(Args: "invalid table element type",
1434 Args: object_error::parse_failed);
1435 }
1436 }
1437 if (Ctx.Ptr != Ctx.End)
1438 return make_error<GenericBinaryError>(Args: "table section ended prematurely",
1439 Args: object_error::parse_failed);
1440 return Error::success();
1441}
1442
1443Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1444 uint32_t Count = readVaruint32(Ctx);
1445 Memories.reserve(n: Count);
1446 while (Count--) {
1447 auto Limits = readLimits(Ctx);
1448 if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1449 HasMemory64 = true;
1450 Memories.push_back(x: Limits);
1451 }
1452 if (Ctx.Ptr != Ctx.End)
1453 return make_error<GenericBinaryError>(Args: "memory section ended prematurely",
1454 Args: object_error::parse_failed);
1455 return Error::success();
1456}
1457
1458Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
1459 TagSection = Sections.size();
1460 uint32_t Count = readVaruint32(Ctx);
1461 Tags.reserve(n: Count);
1462 uint32_t NumTypes = Signatures.size();
1463 while (Count--) {
1464 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1465 return make_error<GenericBinaryError>(Args: "invalid attribute",
1466 Args: object_error::parse_failed);
1467 uint32_t Type = readVaruint32(Ctx);
1468 if (Type >= NumTypes)
1469 return make_error<GenericBinaryError>(Args: "invalid tag type",
1470 Args: object_error::parse_failed);
1471 wasm::WasmTag Tag;
1472 Tag.Index = NumImportedTags + Tags.size();
1473 Tag.SigIndex = Type;
1474 Signatures[Type].Kind = wasm::WasmSignature::Tag;
1475 Tags.push_back(x: Tag);
1476 }
1477
1478 if (Ctx.Ptr != Ctx.End)
1479 return make_error<GenericBinaryError>(Args: "tag section ended prematurely",
1480 Args: object_error::parse_failed);
1481 return Error::success();
1482}
1483
1484Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1485 GlobalSection = Sections.size();
1486 const uint8_t *SectionStart = Ctx.Ptr;
1487 uint32_t Count = readVaruint32(Ctx);
1488 Globals.reserve(n: Count);
1489 while (Count--) {
1490 wasm::WasmGlobal Global;
1491 Global.Index = NumImportedGlobals + Globals.size();
1492 const uint8_t *GlobalStart = Ctx.Ptr;
1493 Global.Offset = static_cast<uint32_t>(GlobalStart - SectionStart);
1494 auto GlobalOpcode = readVaruint32(Ctx);
1495 Global.Type.Type = (uint8_t)parseValType(Ctx, Code: GlobalOpcode);
1496 Global.Type.Mutable = readVaruint1(Ctx);
1497 if (Error Err = readInitExpr(Expr&: Global.InitExpr, Ctx))
1498 return Err;
1499 Global.Size = static_cast<uint32_t>(Ctx.Ptr - GlobalStart);
1500 Globals.push_back(x: Global);
1501 }
1502 if (Ctx.Ptr != Ctx.End)
1503 return make_error<GenericBinaryError>(Args: "global section ended prematurely",
1504 Args: object_error::parse_failed);
1505 return Error::success();
1506}
1507
1508Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1509 uint32_t Count = readVaruint32(Ctx);
1510 Exports.reserve(n: Count);
1511 Symbols.reserve(n: Count);
1512
1513 // Build hash map of export flags for faster cross-referencing
1514 llvm::DenseMap<StringRef, uint32_t> ExportFlags;
1515 if (HasDylinkSection) {
1516 for (const auto &ExportInfo : DylinkInfo.ExportInfo) {
1517 ExportFlags[ExportInfo.Name] = ExportInfo.Flags;
1518 }
1519 }
1520
1521 for (uint32_t I = 0; I < Count; I++) {
1522 wasm::WasmExport Ex;
1523 Ex.Name = readString(Ctx);
1524 Ex.Kind = readUint8(Ctx);
1525 Ex.Index = readVaruint32(Ctx);
1526 const wasm::WasmSignature *Signature = nullptr;
1527 const wasm::WasmGlobalType *GlobalType = nullptr;
1528 const wasm::WasmTableType *TableType = nullptr;
1529 wasm::WasmSymbolInfo Info;
1530 Info.Name = Ex.Name;
1531 Info.Flags = 0;
1532 // For shared objects, symbol flags may be specified in the dylink section
1533 // instead of the export section
1534 if (HasDylinkSection) {
1535 auto It = ExportFlags.find(Val: Ex.Name);
1536 if (It != ExportFlags.end()) {
1537 Info.Flags = It->second;
1538 }
1539 }
1540 switch (Ex.Kind) {
1541 case wasm::WASM_EXTERNAL_FUNCTION: {
1542 if (!isValidFunctionIndex(Index: Ex.Index))
1543 return make_error<GenericBinaryError>(Args: "invalid function export",
1544 Args: object_error::parse_failed);
1545 Info.Kind = wasm::WASM_SYMBOL_TYPE_FUNCTION;
1546 Info.ElementIndex = Ex.Index;
1547 if (isDefinedFunctionIndex(Index: Ex.Index)) {
1548 getDefinedFunction(Index: Ex.Index).ExportName = Ex.Name;
1549 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
1550 wasm::WasmFunction &Function = Functions[FuncIndex];
1551 Signature = &Signatures[Function.SigIndex];
1552 }
1553 // Else the function is imported. LLVM object files don't use this
1554 // pattern and we still treat this as an undefined symbol, but we want to
1555 // parse it without crashing.
1556 break;
1557 }
1558 case wasm::WASM_EXTERNAL_GLOBAL: {
1559 if (!isValidGlobalIndex(Index: Ex.Index))
1560 return make_error<GenericBinaryError>(Args: "invalid global export",
1561 Args: object_error::parse_failed);
1562 Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
1563 uint64_t Offset = 0;
1564 if (isDefinedGlobalIndex(Index: Ex.Index)) {
1565 auto Global = getDefinedGlobal(Index: Ex.Index);
1566 if (!Global.InitExpr.Extended) {
1567 auto Inst = Global.InitExpr.Inst;
1568 if (Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1569 Offset = Inst.Value.Int32;
1570 } else if (Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1571 Offset = Inst.Value.Int64;
1572 }
1573 }
1574 }
1575 Info.DataRef = wasm::WasmDataReference{.Segment: 0, .Offset: Offset, .Size: 0};
1576 break;
1577 }
1578 case wasm::WASM_EXTERNAL_TAG:
1579 if (!isValidTagIndex(Index: Ex.Index))
1580 return make_error<GenericBinaryError>(Args: "invalid tag export",
1581 Args: object_error::parse_failed);
1582 Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;
1583 Info.ElementIndex = Ex.Index;
1584 if (isDefinedTagIndex(Index: Ex.Index)) {
1585 unsigned TagIndex = Ex.Index - NumImportedTags;
1586 Signature = &Signatures[Tags[TagIndex].SigIndex];
1587 }
1588 break;
1589 case wasm::WASM_EXTERNAL_MEMORY:
1590 break;
1591 case wasm::WASM_EXTERNAL_TABLE:
1592 Info.Kind = wasm::WASM_SYMBOL_TYPE_TABLE;
1593 Info.ElementIndex = Ex.Index;
1594 break;
1595 default:
1596 return make_error<GenericBinaryError>(Args: "unexpected export kind",
1597 Args: object_error::parse_failed);
1598 }
1599 Exports.push_back(x: Ex);
1600 if (Ex.Kind != wasm::WASM_EXTERNAL_MEMORY) {
1601 Symbols.emplace_back(args&: Info, args&: GlobalType, args&: TableType, args&: Signature);
1602 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
1603 }
1604 }
1605 if (Ctx.Ptr != Ctx.End)
1606 return make_error<GenericBinaryError>(Args: "export section ended prematurely",
1607 Args: object_error::parse_failed);
1608 return Error::success();
1609}
1610
1611bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1612 return Index < NumImportedFunctions + Functions.size();
1613}
1614
1615bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1616 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1617}
1618
1619bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1620 return Index < NumImportedGlobals + Globals.size();
1621}
1622
1623bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1624 return Index < NumImportedTables + Tables.size();
1625}
1626
1627bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1628 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1629}
1630
1631bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1632 return Index >= NumImportedTables && isValidTableNumber(Index);
1633}
1634
1635bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
1636 return Index < NumImportedTags + Tags.size();
1637}
1638
1639bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
1640 return Index >= NumImportedTags && isValidTagIndex(Index);
1641}
1642
1643bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1644 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1645}
1646
1647bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1648 return Index < Symbols.size() && Symbols[Index].isTypeTable();
1649}
1650
1651bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1652 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1653}
1654
1655bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
1656 return Index < Symbols.size() && Symbols[Index].isTypeTag();
1657}
1658
1659bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1660 return Index < Symbols.size() && Symbols[Index].isTypeData();
1661}
1662
1663bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1664 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1665}
1666
1667wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1668 assert(isDefinedFunctionIndex(Index));
1669 return Functions[Index - NumImportedFunctions];
1670}
1671
1672const wasm::WasmFunction &
1673WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1674 assert(isDefinedFunctionIndex(Index));
1675 return Functions[Index - NumImportedFunctions];
1676}
1677
1678const wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) const {
1679 assert(isDefinedGlobalIndex(Index));
1680 return Globals[Index - NumImportedGlobals];
1681}
1682
1683wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
1684 assert(isDefinedTagIndex(Index));
1685 return Tags[Index - NumImportedTags];
1686}
1687
1688Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1689 StartFunction = readVaruint32(Ctx);
1690 if (!isValidFunctionIndex(Index: StartFunction))
1691 return make_error<GenericBinaryError>(Args: "invalid start function",
1692 Args: object_error::parse_failed);
1693 return Error::success();
1694}
1695
1696Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1697 CodeSection = Sections.size();
1698 uint32_t FunctionCount = readVaruint32(Ctx);
1699 if (FunctionCount != Functions.size()) {
1700 return make_error<GenericBinaryError>(Args: "invalid function count",
1701 Args: object_error::parse_failed);
1702 }
1703
1704 for (uint32_t i = 0; i < FunctionCount; i++) {
1705 wasm::WasmFunction& Function = Functions[i];
1706 const uint8_t *FunctionStart = Ctx.Ptr;
1707 uint32_t Size = readVaruint32(Ctx);
1708 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1709
1710 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1711 Function.Index = NumImportedFunctions + i;
1712 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1713 Function.Size = FunctionEnd - FunctionStart;
1714
1715 uint32_t NumLocalDecls = readVaruint32(Ctx);
1716 Function.Locals.reserve(n: NumLocalDecls);
1717 while (NumLocalDecls--) {
1718 wasm::WasmLocalDecl Decl;
1719 Decl.Count = readVaruint32(Ctx);
1720 Decl.Type = readUint8(Ctx);
1721 Function.Locals.push_back(x: Decl);
1722 }
1723
1724 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1725 // Ensure that Function is within Ctx's buffer.
1726 if (Ctx.Ptr + BodySize > Ctx.End) {
1727 return make_error<GenericBinaryError>(Args: "Function extends beyond buffer",
1728 Args: object_error::parse_failed);
1729 }
1730 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1731 // This will be set later when reading in the linking metadata section.
1732 Function.Comdat = UINT32_MAX;
1733 Ctx.Ptr += BodySize;
1734 assert(Ctx.Ptr == FunctionEnd);
1735 }
1736 if (Ctx.Ptr != Ctx.End)
1737 return make_error<GenericBinaryError>(Args: "code section ended prematurely",
1738 Args: object_error::parse_failed);
1739 return Error::success();
1740}
1741
1742Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1743 uint32_t Count = readVaruint32(Ctx);
1744 ElemSegments.reserve(n: Count);
1745 while (Count--) {
1746 wasm::WasmElemSegment Segment;
1747 Segment.Flags = readVaruint32(Ctx);
1748
1749 uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1750 wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1751 wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1752 if (Segment.Flags & ~SupportedFlags)
1753 return make_error<GenericBinaryError>(
1754 Args: "Unsupported flags for element segment", Args: object_error::parse_failed);
1755
1756 wasm::ElemSegmentMode Mode;
1757 if ((Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) == 0) {
1758 Mode = wasm::ElemSegmentMode::Active;
1759 } else if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE) {
1760 Mode = wasm::ElemSegmentMode::Declarative;
1761 } else {
1762 Mode = wasm::ElemSegmentMode::Passive;
1763 }
1764 bool HasTableNumber =
1765 Mode == wasm::ElemSegmentMode::Active &&
1766 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);
1767 bool HasElemKind =
1768 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) &&
1769 !(Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
1770 bool HasElemType =
1771 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) &&
1772 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
1773 bool HasInitExprs =
1774 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
1775
1776 if (HasTableNumber)
1777 Segment.TableNumber = readVaruint32(Ctx);
1778 else
1779 Segment.TableNumber = 0;
1780
1781 if (!isValidTableNumber(Index: Segment.TableNumber))
1782 return make_error<GenericBinaryError>(Args: "invalid TableNumber",
1783 Args: object_error::parse_failed);
1784
1785 if (Mode != wasm::ElemSegmentMode::Active) {
1786 Segment.Offset.Extended = false;
1787 Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1788 Segment.Offset.Inst.Value.Int32 = 0;
1789 } else {
1790 if (Error Err = readInitExpr(Expr&: Segment.Offset, Ctx))
1791 return Err;
1792 }
1793
1794 if (HasElemKind) {
1795 auto ElemKind = readVaruint32(Ctx);
1796 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1797 Segment.ElemKind = parseValType(Ctx, Code: ElemKind);
1798 if (Segment.ElemKind != wasm::ValType::FUNCREF &&
1799 Segment.ElemKind != wasm::ValType::EXTERNREF &&
1800 Segment.ElemKind != wasm::ValType::EXNREF &&
1801 Segment.ElemKind != wasm::ValType::OTHERREF) {
1802 return make_error<GenericBinaryError>(Args: "invalid elem type",
1803 Args: object_error::parse_failed);
1804 }
1805 } else {
1806 if (ElemKind != 0)
1807 return make_error<GenericBinaryError>(Args: "invalid elem type",
1808 Args: object_error::parse_failed);
1809 Segment.ElemKind = wasm::ValType::FUNCREF;
1810 }
1811 } else if (HasElemType) {
1812 auto ElemType = parseValType(Ctx, Code: readVaruint32(Ctx));
1813 Segment.ElemKind = ElemType;
1814 } else {
1815 Segment.ElemKind = wasm::ValType::FUNCREF;
1816 }
1817
1818 uint32_t NumElems = readVaruint32(Ctx);
1819
1820 if (HasInitExprs) {
1821 while (NumElems--) {
1822 wasm::WasmInitExpr Expr;
1823 if (Error Err = readInitExpr(Expr, Ctx))
1824 return Err;
1825 }
1826 } else {
1827 while (NumElems--) {
1828 Segment.Functions.push_back(x: readVaruint32(Ctx));
1829 }
1830 }
1831 ElemSegments.push_back(x: Segment);
1832 }
1833 if (Ctx.Ptr != Ctx.End)
1834 return make_error<GenericBinaryError>(Args: "elem section ended prematurely",
1835 Args: object_error::parse_failed);
1836 return Error::success();
1837}
1838
1839Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1840 DataSection = Sections.size();
1841 uint32_t Count = readVaruint32(Ctx);
1842 if (DataCount && Count != *DataCount)
1843 return make_error<GenericBinaryError>(
1844 Args: "number of data segments does not match DataCount section");
1845 DataSegments.reserve(n: Count);
1846 while (Count--) {
1847 WasmSegment Segment;
1848 Segment.Data.InitFlags = readVaruint32(Ctx);
1849 Segment.Data.MemoryIndex =
1850 (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1851 ? readVaruint32(Ctx)
1852 : 0;
1853 if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1854 if (Error Err = readInitExpr(Expr&: Segment.Data.Offset, Ctx))
1855 return Err;
1856 } else {
1857 Segment.Data.Offset.Extended = false;
1858 Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1859 Segment.Data.Offset.Inst.Value.Int32 = 0;
1860 }
1861 uint32_t Size = readVaruint32(Ctx);
1862 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1863 return make_error<GenericBinaryError>(Args: "invalid segment size",
1864 Args: object_error::parse_failed);
1865 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1866 // The rest of these Data fields are set later, when reading in the linking
1867 // metadata section.
1868 Segment.Data.Alignment = 0;
1869 Segment.Data.LinkingFlags = 0;
1870 Segment.Data.Comdat = UINT32_MAX;
1871 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1872 Ctx.Ptr += Size;
1873 DataSegments.push_back(x: Segment);
1874 }
1875 if (Ctx.Ptr != Ctx.End)
1876 return make_error<GenericBinaryError>(Args: "data section ended prematurely",
1877 Args: object_error::parse_failed);
1878 return Error::success();
1879}
1880
1881Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1882 DataCount = readVaruint32(Ctx);
1883 return Error::success();
1884}
1885
1886const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1887 return Header;
1888}
1889
1890void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1891
1892Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1893 uint32_t Result = SymbolRef::SF_None;
1894 const WasmSymbol &Sym = getWasmSymbol(Symb);
1895
1896 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1897 if (Sym.isBindingWeak())
1898 Result |= SymbolRef::SF_Weak;
1899 if (!Sym.isBindingLocal())
1900 Result |= SymbolRef::SF_Global;
1901 if (Sym.isHidden())
1902 Result |= SymbolRef::SF_Hidden;
1903 if (!Sym.isDefined())
1904 Result |= SymbolRef::SF_Undefined;
1905 if (Sym.isTypeFunction())
1906 Result |= SymbolRef::SF_Executable;
1907 return Result;
1908}
1909
1910basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1911 DataRefImpl Ref;
1912 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1913 Ref.d.b = 0; // Symbol index
1914 return BasicSymbolRef(Ref, this);
1915}
1916
1917basic_symbol_iterator WasmObjectFile::symbol_end() const {
1918 DataRefImpl Ref;
1919 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1920 Ref.d.b = Symbols.size(); // Symbol index
1921 return BasicSymbolRef(Ref, this);
1922}
1923
1924const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1925 return Symbols[Symb.d.b];
1926}
1927
1928const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1929 return getWasmSymbol(Symb: Symb.getRawDataRefImpl());
1930}
1931
1932Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1933 return getWasmSymbol(Symb).Info.Name;
1934}
1935
1936Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1937 auto &Sym = getWasmSymbol(Symb);
1938 if (!Sym.isDefined())
1939 return 0;
1940 Expected<section_iterator> Sec = getSymbolSection(Symb);
1941 if (!Sec)
1942 return Sec.takeError();
1943 uint32_t SectionAddress = getSectionAddress(Sec: Sec.get()->getRawDataRefImpl());
1944 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1945 isDefinedFunctionIndex(Index: Sym.Info.ElementIndex)) {
1946 return getDefinedFunction(Index: Sym.Info.ElementIndex).CodeSectionOffset +
1947 SectionAddress;
1948 }
1949 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL &&
1950 isDefinedGlobalIndex(Index: Sym.Info.ElementIndex)) {
1951 return getDefinedGlobal(Index: Sym.Info.ElementIndex).Offset + SectionAddress;
1952 }
1953
1954 return getSymbolValue(Symb);
1955}
1956
1957uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1958 switch (Sym.Info.Kind) {
1959 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1960 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1961 case wasm::WASM_SYMBOL_TYPE_TAG:
1962 case wasm::WASM_SYMBOL_TYPE_TABLE:
1963 return Sym.Info.ElementIndex;
1964 case wasm::WASM_SYMBOL_TYPE_DATA: {
1965 // The value of a data symbol is the segment offset, plus the symbol
1966 // offset within the segment.
1967 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1968 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1969 if (Segment.Offset.Extended) {
1970 llvm_unreachable("extended init exprs not supported");
1971 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1972 return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1973 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1974 return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1975 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_GLOBAL_GET) {
1976 return Sym.Info.DataRef.Offset;
1977 } else {
1978 llvm_unreachable("unknown init expr opcode");
1979 }
1980 }
1981 case wasm::WASM_SYMBOL_TYPE_SECTION:
1982 return 0;
1983 }
1984 llvm_unreachable("invalid symbol type");
1985}
1986
1987uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1988 return getWasmSymbolValue(Sym: getWasmSymbol(Symb));
1989}
1990
1991uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1992 llvm_unreachable("not yet implemented");
1993 return 0;
1994}
1995
1996uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1997 llvm_unreachable("not yet implemented");
1998 return 0;
1999}
2000
2001Expected<SymbolRef::Type>
2002WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
2003 const WasmSymbol &Sym = getWasmSymbol(Symb);
2004
2005 switch (Sym.Info.Kind) {
2006 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
2007 return SymbolRef::ST_Function;
2008 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
2009 return SymbolRef::ST_Other;
2010 case wasm::WASM_SYMBOL_TYPE_DATA:
2011 return SymbolRef::ST_Data;
2012 case wasm::WASM_SYMBOL_TYPE_SECTION:
2013 return SymbolRef::ST_Debug;
2014 case wasm::WASM_SYMBOL_TYPE_TAG:
2015 return SymbolRef::ST_Other;
2016 case wasm::WASM_SYMBOL_TYPE_TABLE:
2017 return SymbolRef::ST_Other;
2018 }
2019
2020 llvm_unreachable("unknown WasmSymbol::SymbolType");
2021 return SymbolRef::ST_Other;
2022}
2023
2024Expected<section_iterator>
2025WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
2026 const WasmSymbol &Sym = getWasmSymbol(Symb);
2027 if (Sym.isUndefined())
2028 return section_end();
2029
2030 DataRefImpl Ref;
2031 Ref.d.a = getSymbolSectionIdImpl(Symb: Sym);
2032 return section_iterator(SectionRef(Ref, this));
2033}
2034
2035uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
2036 const WasmSymbol &Sym = getWasmSymbol(Symb);
2037 return getSymbolSectionIdImpl(Symb: Sym);
2038}
2039
2040uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
2041 switch (Sym.Info.Kind) {
2042 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
2043 return CodeSection;
2044 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
2045 return GlobalSection;
2046 case wasm::WASM_SYMBOL_TYPE_DATA:
2047 return DataSection;
2048 case wasm::WASM_SYMBOL_TYPE_SECTION:
2049 return Sym.Info.ElementIndex;
2050 case wasm::WASM_SYMBOL_TYPE_TAG:
2051 return TagSection;
2052 case wasm::WASM_SYMBOL_TYPE_TABLE:
2053 return TableSection;
2054 default:
2055 llvm_unreachable("unknown WasmSymbol::SymbolType");
2056 }
2057}
2058
2059uint32_t WasmObjectFile::getSymbolSize(SymbolRef Symb) const {
2060 const WasmSymbol &Sym = getWasmSymbol(Symb);
2061 if (!Sym.isDefined())
2062 return 0;
2063 if (Sym.isTypeGlobal())
2064 return getDefinedGlobal(Index: Sym.Info.ElementIndex).Size;
2065 if (Sym.isTypeData())
2066 return Sym.Info.DataRef.Size;
2067 if (Sym.isTypeFunction())
2068 return functions()[Sym.Info.ElementIndex - getNumImportedFunctions()].Size;
2069 // Currently symbol size is only tracked for data segments and functions. In
2070 // principle we could also track size (e.g. binary size) for tables, globals
2071 // and element segments etc too.
2072 return 0;
2073}
2074
2075void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
2076
2077Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
2078 const WasmSection &S = Sections[Sec.d.a];
2079 if (S.Type == wasm::WASM_SEC_CUSTOM)
2080 return S.Name;
2081 if (S.Type > wasm::WASM_SEC_LAST_KNOWN)
2082 return createStringError(EC: object_error::invalid_section_index, S: "");
2083 return wasm::sectionTypeToString(type: S.Type);
2084}
2085
2086uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const {
2087 // For object files, use 0 for section addresses, and section offsets for
2088 // symbol addresses. For linked files, use file offsets.
2089 // See also getSymbolAddress.
2090 return isRelocatableObject() || isSharedObject() ? 0
2091 : Sections[Sec.d.a].Offset;
2092}
2093
2094uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
2095 return Sec.d.a;
2096}
2097
2098uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
2099 const WasmSection &S = Sections[Sec.d.a];
2100 return S.Content.size();
2101}
2102
2103Expected<ArrayRef<uint8_t>>
2104WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
2105 const WasmSection &S = Sections[Sec.d.a];
2106 // This will never fail since wasm sections can never be empty (user-sections
2107 // must have a name and non-user sections each have a defined structure).
2108 return S.Content;
2109}
2110
2111uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
2112 return 1;
2113}
2114
2115bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
2116 return false;
2117}
2118
2119bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
2120 return getWasmSection(Ref: Sec).Type == wasm::WASM_SEC_CODE;
2121}
2122
2123bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
2124 return getWasmSection(Ref: Sec).Type == wasm::WASM_SEC_DATA;
2125}
2126
2127bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
2128
2129bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
2130
2131relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
2132 DataRefImpl RelocRef;
2133 RelocRef.d.a = Ref.d.a;
2134 RelocRef.d.b = 0;
2135 return relocation_iterator(RelocationRef(RelocRef, this));
2136}
2137
2138relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
2139 const WasmSection &Sec = getWasmSection(Ref);
2140 DataRefImpl RelocRef;
2141 RelocRef.d.a = Ref.d.a;
2142 RelocRef.d.b = Sec.Relocations.size();
2143 return relocation_iterator(RelocationRef(RelocRef, this));
2144}
2145
2146void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
2147
2148uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
2149 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2150 return Rel.Offset;
2151}
2152
2153symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
2154 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2155 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
2156 return symbol_end();
2157 DataRefImpl Sym;
2158 Sym.d.a = 1;
2159 Sym.d.b = Rel.Index;
2160 return symbol_iterator(SymbolRef(Sym, this));
2161}
2162
2163uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
2164 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2165 return Rel.Type;
2166}
2167
2168void WasmObjectFile::getRelocationTypeName(
2169 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
2170 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2171 StringRef Res = "Unknown";
2172
2173#define WASM_RELOC(name, value) \
2174 case wasm::name: \
2175 Res = #name; \
2176 break;
2177
2178 switch (Rel.Type) {
2179#include "llvm/BinaryFormat/WasmRelocs.def"
2180 }
2181
2182#undef WASM_RELOC
2183
2184 Result.append(in_start: Res.begin(), in_end: Res.end());
2185}
2186
2187section_iterator WasmObjectFile::section_begin() const {
2188 DataRefImpl Ref;
2189 Ref.d.a = 0;
2190 return section_iterator(SectionRef(Ref, this));
2191}
2192
2193section_iterator WasmObjectFile::section_end() const {
2194 DataRefImpl Ref;
2195 Ref.d.a = Sections.size();
2196 return section_iterator(SectionRef(Ref, this));
2197}
2198
2199uint8_t WasmObjectFile::getBytesInAddress() const {
2200 return getArch() == Triple::wasm64 ? 8 : 4;
2201}
2202
2203StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
2204
2205Triple::ArchType WasmObjectFile::getArch() const {
2206 if (!LinkingData.TargetArch.empty())
2207 return Triple(LinkingData.TargetArch).getArch();
2208 if (!DylinkInfo.TargetArch.empty())
2209 return Triple(DylinkInfo.TargetArch).getArch();
2210 // Fall back to the HasMemory64 heuristic for backwards compatibility with
2211 // older object files/shared libraries that lack target architecture metadata,
2212 // as well as final executables that lack custom linking/dylink sections.
2213 return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
2214}
2215
2216Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {
2217 return SubtargetFeatures();
2218}
2219
2220bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
2221
2222bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
2223
2224const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
2225 assert(Ref.d.a < Sections.size());
2226 return Sections[Ref.d.a];
2227}
2228
2229const WasmSection &
2230WasmObjectFile::getWasmSection(const SectionRef &Section) const {
2231 return getWasmSection(Ref: Section.getRawDataRefImpl());
2232}
2233
2234const wasm::WasmRelocation &
2235WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
2236 return getWasmRelocation(Ref: Ref.getRawDataRefImpl());
2237}
2238
2239const wasm::WasmRelocation &
2240WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
2241 assert(Ref.d.a < Sections.size());
2242 const WasmSection &Sec = Sections[Ref.d.a];
2243 assert(Ref.d.b < Sec.Relocations.size());
2244 return Sec.Relocations[Ref.d.b];
2245}
2246
2247int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
2248 StringRef CustomSectionName) {
2249 switch (ID) {
2250 case wasm::WASM_SEC_CUSTOM:
2251 return StringSwitch<unsigned>(CustomSectionName)
2252 .Case(S: "dylink", Value: WASM_SEC_ORDER_DYLINK)
2253 .Case(S: "dylink.0", Value: WASM_SEC_ORDER_DYLINK)
2254 .Case(S: "linking", Value: WASM_SEC_ORDER_LINKING)
2255 .StartsWith(S: "reloc.", Value: WASM_SEC_ORDER_RELOC)
2256 .Case(S: "name", Value: WASM_SEC_ORDER_NAME)
2257 .Case(S: "producers", Value: WASM_SEC_ORDER_PRODUCERS)
2258 .Case(S: "target_features", Value: WASM_SEC_ORDER_TARGET_FEATURES)
2259 .Default(Value: WASM_SEC_ORDER_NONE);
2260 case wasm::WASM_SEC_TYPE:
2261 return WASM_SEC_ORDER_TYPE;
2262 case wasm::WASM_SEC_IMPORT:
2263 return WASM_SEC_ORDER_IMPORT;
2264 case wasm::WASM_SEC_FUNCTION:
2265 return WASM_SEC_ORDER_FUNCTION;
2266 case wasm::WASM_SEC_TABLE:
2267 return WASM_SEC_ORDER_TABLE;
2268 case wasm::WASM_SEC_MEMORY:
2269 return WASM_SEC_ORDER_MEMORY;
2270 case wasm::WASM_SEC_GLOBAL:
2271 return WASM_SEC_ORDER_GLOBAL;
2272 case wasm::WASM_SEC_EXPORT:
2273 return WASM_SEC_ORDER_EXPORT;
2274 case wasm::WASM_SEC_START:
2275 return WASM_SEC_ORDER_START;
2276 case wasm::WASM_SEC_ELEM:
2277 return WASM_SEC_ORDER_ELEM;
2278 case wasm::WASM_SEC_CODE:
2279 return WASM_SEC_ORDER_CODE;
2280 case wasm::WASM_SEC_DATA:
2281 return WASM_SEC_ORDER_DATA;
2282 case wasm::WASM_SEC_DATACOUNT:
2283 return WASM_SEC_ORDER_DATACOUNT;
2284 case wasm::WASM_SEC_TAG:
2285 return WASM_SEC_ORDER_TAG;
2286 default:
2287 return WASM_SEC_ORDER_NONE;
2288 }
2289}
2290
2291// Represents the edges in a directed graph where any node B reachable from node
2292// A is not allowed to appear before A in the section ordering, but may appear
2293// afterward.
2294int WasmSectionOrderChecker::DisallowedPredecessors
2295 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
2296 // WASM_SEC_ORDER_NONE
2297 {},
2298 // WASM_SEC_ORDER_TYPE
2299 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
2300 // WASM_SEC_ORDER_IMPORT
2301 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
2302 // WASM_SEC_ORDER_FUNCTION
2303 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
2304 // WASM_SEC_ORDER_TABLE
2305 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
2306 // WASM_SEC_ORDER_MEMORY
2307 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
2308 // WASM_SEC_ORDER_TAG
2309 {WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
2310 // WASM_SEC_ORDER_GLOBAL
2311 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
2312 // WASM_SEC_ORDER_EXPORT
2313 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
2314 // WASM_SEC_ORDER_START
2315 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
2316 // WASM_SEC_ORDER_ELEM
2317 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
2318 // WASM_SEC_ORDER_DATACOUNT
2319 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
2320 // WASM_SEC_ORDER_CODE
2321 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
2322 // WASM_SEC_ORDER_DATA
2323 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
2324
2325 // Custom Sections
2326 // WASM_SEC_ORDER_DYLINK
2327 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
2328 // WASM_SEC_ORDER_LINKING
2329 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
2330 // WASM_SEC_ORDER_RELOC (can be repeated)
2331 {},
2332 // WASM_SEC_ORDER_NAME
2333 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
2334 // WASM_SEC_ORDER_PRODUCERS
2335 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
2336 // WASM_SEC_ORDER_TARGET_FEATURES
2337 {WASM_SEC_ORDER_TARGET_FEATURES}};
2338
2339bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
2340 StringRef CustomSectionName) {
2341 int Order = getSectionOrder(ID, CustomSectionName);
2342 if (Order == WASM_SEC_ORDER_NONE)
2343 return true;
2344
2345 // Disallowed predecessors we need to check for
2346 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
2347
2348 // Keep track of completed checks to avoid repeating work
2349 bool Checked[WASM_NUM_SEC_ORDERS] = {};
2350
2351 int Curr = Order;
2352 while (true) {
2353 // Add new disallowed predecessors to work list
2354 for (size_t I = 0;; ++I) {
2355 int Next = DisallowedPredecessors[Curr][I];
2356 if (Next == WASM_SEC_ORDER_NONE)
2357 break;
2358 if (Checked[Next])
2359 continue;
2360 WorkList.push_back(Elt: Next);
2361 Checked[Next] = true;
2362 }
2363
2364 if (WorkList.empty())
2365 break;
2366
2367 // Consider next disallowed predecessor
2368 Curr = WorkList.pop_back_val();
2369 if (Seen[Curr])
2370 return false;
2371 }
2372
2373 // Have not seen any disallowed predecessors
2374 Seen[Order] = true;
2375 return true;
2376}
2377