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