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/STLExtras.h"
12 #include "llvm/ADT/SmallSet.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/ADT/Triple.h"
17 #include "llvm/BinaryFormat/Wasm.h"
18 #include "llvm/MC/SubtargetFeature.h"
19 #include "llvm/Object/Binary.h"
20 #include "llvm/Object/Error.h"
21 #include "llvm/Object/ObjectFile.h"
22 #include "llvm/Object/SymbolicFile.h"
23 #include "llvm/Object/Wasm.h"
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Support/Error.h"
26 #include "llvm/Support/ErrorHandling.h"
27 #include "llvm/Support/LEB128.h"
28 #include "llvm/Support/ScopedPrinter.h"
33 #include <system_error>
35 #define DEBUG_TYPE "wasm-object"
38 using namespace object;
40 void WasmSymbol::print(raw_ostream &Out) const {
41 Out << "Name=" << Info.Name
42 << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind))
43 << ", Flags=" << Info.Flags;
45 Out << ", ElemIndex=" << Info.ElementIndex;
46 } else if (isDefined()) {
47 Out << ", Segment=" << Info.DataRef.Segment;
48 Out << ", Offset=" << Info.DataRef.Offset;
49 Out << ", Size=" << Info.DataRef.Size;
53 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
54 LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
57 Expected<std::unique_ptr<WasmObjectFile>>
58 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
59 Error Err = Error::success();
60 auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
62 return std::move(Err);
64 return std::move(ObjectFile);
67 #define VARINT7_MAX ((1 << 7) - 1)
68 #define VARINT7_MIN (-(1 << 7))
69 #define VARUINT7_MAX (1 << 7)
70 #define VARUINT1_MAX (1)
72 static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
73 if (Ctx.Ptr == Ctx.End)
74 report_fatal_error("EOF while reading uint8");
78 static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
79 if (Ctx.Ptr + 4 > Ctx.End)
80 report_fatal_error("EOF while reading uint32");
81 uint32_t Result = support::endian::read32le(Ctx.Ptr);
86 static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
87 if (Ctx.Ptr + 4 > Ctx.End)
88 report_fatal_error("EOF while reading float64");
90 memcpy(&Result, Ctx.Ptr, sizeof(Result));
91 Ctx.Ptr += sizeof(Result);
95 static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
96 if (Ctx.Ptr + 8 > Ctx.End)
97 report_fatal_error("EOF while reading float64");
99 memcpy(&Result, Ctx.Ptr, sizeof(Result));
100 Ctx.Ptr += sizeof(Result);
104 static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
106 const char *Error = nullptr;
107 uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
109 report_fatal_error(Error);
114 static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
115 uint32_t StringLen = readULEB128(Ctx);
116 if (Ctx.Ptr + StringLen > Ctx.End)
117 report_fatal_error("EOF while reading string");
119 StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
120 Ctx.Ptr += StringLen;
124 static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
126 const char *Error = nullptr;
127 uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
129 report_fatal_error(Error);
134 static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
135 int64_t Result = readLEB128(Ctx);
136 if (Result > VARUINT1_MAX || Result < 0)
137 report_fatal_error("LEB is outside Varuint1 range");
141 static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
142 int64_t Result = readLEB128(Ctx);
143 if (Result > INT32_MAX || Result < INT32_MIN)
144 report_fatal_error("LEB is outside Varint32 range");
148 static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
149 uint64_t Result = readULEB128(Ctx);
150 if (Result > UINT32_MAX)
151 report_fatal_error("LEB is outside Varuint32 range");
155 static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
156 return readLEB128(Ctx);
159 static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
160 return readULEB128(Ctx);
163 static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
164 return readUint8(Ctx);
167 static Error readInitExpr(wasm::WasmInitExpr &Expr,
168 WasmObjectFile::ReadContext &Ctx) {
169 Expr.Opcode = readOpcode(Ctx);
171 switch (Expr.Opcode) {
172 case wasm::WASM_OPCODE_I32_CONST:
173 Expr.Value.Int32 = readVarint32(Ctx);
175 case wasm::WASM_OPCODE_I64_CONST:
176 Expr.Value.Int64 = readVarint64(Ctx);
178 case wasm::WASM_OPCODE_F32_CONST:
179 Expr.Value.Float32 = readFloat32(Ctx);
181 case wasm::WASM_OPCODE_F64_CONST:
182 Expr.Value.Float64 = readFloat64(Ctx);
184 case wasm::WASM_OPCODE_GLOBAL_GET:
185 Expr.Value.Global = readULEB128(Ctx);
187 case wasm::WASM_OPCODE_REF_NULL: {
188 wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
189 if (Ty != wasm::ValType::EXTERNREF) {
190 return make_error<GenericBinaryError>("Invalid type for ref.null",
191 object_error::parse_failed);
196 return make_error<GenericBinaryError>("Invalid opcode in init_expr",
197 object_error::parse_failed);
200 uint8_t EndOpcode = readOpcode(Ctx);
201 if (EndOpcode != wasm::WASM_OPCODE_END) {
202 return make_error<GenericBinaryError>("Invalid init_expr",
203 object_error::parse_failed);
205 return Error::success();
208 static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
209 wasm::WasmLimits Result;
210 Result.Flags = readVaruint32(Ctx);
211 Result.Initial = readVaruint64(Ctx);
212 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
213 Result.Maximum = readVaruint64(Ctx);
217 static wasm::WasmTable readTable(WasmObjectFile::ReadContext &Ctx) {
218 wasm::WasmTable Table;
219 Table.ElemType = readUint8(Ctx);
220 Table.Limits = readLimits(Ctx);
224 static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
225 WasmSectionOrderChecker &Checker) {
226 Section.Offset = Ctx.Ptr - Ctx.Start;
227 Section.Type = readUint8(Ctx);
228 LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
229 uint32_t Size = readVaruint32(Ctx);
231 return make_error<StringError>("Zero length section",
232 object_error::parse_failed);
233 if (Ctx.Ptr + Size > Ctx.End)
234 return make_error<StringError>("Section too large",
235 object_error::parse_failed);
236 if (Section.Type == wasm::WASM_SEC_CUSTOM) {
237 WasmObjectFile::ReadContext SectionCtx;
238 SectionCtx.Start = Ctx.Ptr;
239 SectionCtx.Ptr = Ctx.Ptr;
240 SectionCtx.End = Ctx.Ptr + Size;
242 Section.Name = readString(SectionCtx);
244 uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
245 Ctx.Ptr += SectionNameSize;
246 Size -= SectionNameSize;
249 if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
250 return make_error<StringError>("Out of order section type: " +
251 llvm::to_string(Section.Type),
252 object_error::parse_failed);
255 Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
257 return Error::success();
260 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
261 : ObjectFile(Binary::ID_Wasm, Buffer) {
262 ErrorAsOutParameter ErrAsOutParam(&Err);
263 Header.Magic = getData().substr(0, 4);
264 if (Header.Magic != StringRef("\0asm", 4)) {
266 make_error<StringError>("Bad magic number", object_error::parse_failed);
271 Ctx.Start = getData().bytes_begin();
272 Ctx.Ptr = Ctx.Start + 4;
273 Ctx.End = Ctx.Start + getData().size();
275 if (Ctx.Ptr + 4 > Ctx.End) {
276 Err = make_error<StringError>("Missing version number",
277 object_error::parse_failed);
281 Header.Version = readUint32(Ctx);
282 if (Header.Version != wasm::WasmVersion) {
283 Err = make_error<StringError>("Bad version number",
284 object_error::parse_failed);
289 WasmSectionOrderChecker Checker;
290 while (Ctx.Ptr < Ctx.End) {
291 if ((Err = readSection(Sec, Ctx, Checker)))
293 if ((Err = parseSection(Sec)))
296 Sections.push_back(Sec);
300 Error WasmObjectFile::parseSection(WasmSection &Sec) {
302 Ctx.Start = Sec.Content.data();
303 Ctx.End = Ctx.Start + Sec.Content.size();
306 case wasm::WASM_SEC_CUSTOM:
307 return parseCustomSection(Sec, Ctx);
308 case wasm::WASM_SEC_TYPE:
309 return parseTypeSection(Ctx);
310 case wasm::WASM_SEC_IMPORT:
311 return parseImportSection(Ctx);
312 case wasm::WASM_SEC_FUNCTION:
313 return parseFunctionSection(Ctx);
314 case wasm::WASM_SEC_TABLE:
315 return parseTableSection(Ctx);
316 case wasm::WASM_SEC_MEMORY:
317 return parseMemorySection(Ctx);
318 case wasm::WASM_SEC_EVENT:
319 return parseEventSection(Ctx);
320 case wasm::WASM_SEC_GLOBAL:
321 return parseGlobalSection(Ctx);
322 case wasm::WASM_SEC_EXPORT:
323 return parseExportSection(Ctx);
324 case wasm::WASM_SEC_START:
325 return parseStartSection(Ctx);
326 case wasm::WASM_SEC_ELEM:
327 return parseElemSection(Ctx);
328 case wasm::WASM_SEC_CODE:
329 return parseCodeSection(Ctx);
330 case wasm::WASM_SEC_DATA:
331 return parseDataSection(Ctx);
332 case wasm::WASM_SEC_DATACOUNT:
333 return parseDataCountSection(Ctx);
335 return make_error<GenericBinaryError>(
336 "Invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
340 Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
341 // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
342 HasDylinkSection = true;
343 DylinkInfo.MemorySize = readVaruint32(Ctx);
344 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
345 DylinkInfo.TableSize = readVaruint32(Ctx);
346 DylinkInfo.TableAlignment = readVaruint32(Ctx);
347 uint32_t Count = readVaruint32(Ctx);
349 DylinkInfo.Needed.push_back(readString(Ctx));
351 if (Ctx.Ptr != Ctx.End)
352 return make_error<GenericBinaryError>("dylink section ended prematurely",
353 object_error::parse_failed);
354 return Error::success();
357 Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
358 llvm::DenseSet<uint64_t> Seen;
359 if (FunctionTypes.size() && !SeenCodeSection) {
360 return make_error<GenericBinaryError>("Names must come after code section",
361 object_error::parse_failed);
364 while (Ctx.Ptr < Ctx.End) {
365 uint8_t Type = readUint8(Ctx);
366 uint32_t Size = readVaruint32(Ctx);
367 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
369 case wasm::WASM_NAMES_FUNCTION: {
370 uint32_t Count = readVaruint32(Ctx);
372 uint32_t Index = readVaruint32(Ctx);
373 if (!Seen.insert(Index).second)
374 return make_error<GenericBinaryError>("Function named more than once",
375 object_error::parse_failed);
376 StringRef Name = readString(Ctx);
377 if (!isValidFunctionIndex(Index) || Name.empty())
378 return make_error<GenericBinaryError>("Invalid name entry",
379 object_error::parse_failed);
380 DebugNames.push_back(wasm::WasmFunctionName{Index, Name});
381 if (isDefinedFunctionIndex(Index))
382 getDefinedFunction(Index).DebugName = Name;
386 // Ignore local names for now
387 case wasm::WASM_NAMES_LOCAL:
392 if (Ctx.Ptr != SubSectionEnd)
393 return make_error<GenericBinaryError>(
394 "Name sub-section ended prematurely", object_error::parse_failed);
397 if (Ctx.Ptr != Ctx.End)
398 return make_error<GenericBinaryError>("Name section ended prematurely",
399 object_error::parse_failed);
400 return Error::success();
403 Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
404 HasLinkingSection = true;
405 if (FunctionTypes.size() && !SeenCodeSection) {
406 return make_error<GenericBinaryError>(
407 "Linking data must come after code section",
408 object_error::parse_failed);
411 LinkingData.Version = readVaruint32(Ctx);
412 if (LinkingData.Version != wasm::WasmMetadataVersion) {
413 return make_error<GenericBinaryError>(
414 "Unexpected metadata version: " + Twine(LinkingData.Version) +
415 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
416 object_error::parse_failed);
419 const uint8_t *OrigEnd = Ctx.End;
420 while (Ctx.Ptr < OrigEnd) {
422 uint8_t Type = readUint8(Ctx);
423 uint32_t Size = readVaruint32(Ctx);
424 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
426 Ctx.End = Ctx.Ptr + Size;
428 case wasm::WASM_SYMBOL_TABLE:
429 if (Error Err = parseLinkingSectionSymtab(Ctx))
432 case wasm::WASM_SEGMENT_INFO: {
433 uint32_t Count = readVaruint32(Ctx);
434 if (Count > DataSegments.size())
435 return make_error<GenericBinaryError>("Too many segment names",
436 object_error::parse_failed);
437 for (uint32_t I = 0; I < Count; I++) {
438 DataSegments[I].Data.Name = readString(Ctx);
439 DataSegments[I].Data.Alignment = readVaruint32(Ctx);
440 DataSegments[I].Data.LinkerFlags = readVaruint32(Ctx);
444 case wasm::WASM_INIT_FUNCS: {
445 uint32_t Count = readVaruint32(Ctx);
446 LinkingData.InitFunctions.reserve(Count);
447 for (uint32_t I = 0; I < Count; I++) {
448 wasm::WasmInitFunc Init;
449 Init.Priority = readVaruint32(Ctx);
450 Init.Symbol = readVaruint32(Ctx);
451 if (!isValidFunctionSymbol(Init.Symbol))
452 return make_error<GenericBinaryError>("Invalid function symbol: " +
454 object_error::parse_failed);
455 LinkingData.InitFunctions.emplace_back(Init);
459 case wasm::WASM_COMDAT_INFO:
460 if (Error Err = parseLinkingSectionComdat(Ctx))
467 if (Ctx.Ptr != Ctx.End)
468 return make_error<GenericBinaryError>(
469 "Linking sub-section ended prematurely", object_error::parse_failed);
471 if (Ctx.Ptr != OrigEnd)
472 return make_error<GenericBinaryError>("Linking section ended prematurely",
473 object_error::parse_failed);
474 return Error::success();
477 Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
478 uint32_t Count = readVaruint32(Ctx);
479 LinkingData.SymbolTable.reserve(Count);
480 Symbols.reserve(Count);
481 StringSet<> SymbolNames;
483 std::vector<wasm::WasmImport *> ImportedGlobals;
484 std::vector<wasm::WasmImport *> ImportedFunctions;
485 std::vector<wasm::WasmImport *> ImportedEvents;
486 ImportedGlobals.reserve(Imports.size());
487 ImportedFunctions.reserve(Imports.size());
488 ImportedEvents.reserve(Imports.size());
489 for (auto &I : Imports) {
490 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
491 ImportedFunctions.emplace_back(&I);
492 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
493 ImportedGlobals.emplace_back(&I);
494 else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
495 ImportedEvents.emplace_back(&I);
499 wasm::WasmSymbolInfo Info;
500 const wasm::WasmSignature *Signature = nullptr;
501 const wasm::WasmGlobalType *GlobalType = nullptr;
502 const wasm::WasmEventType *EventType = nullptr;
504 Info.Kind = readUint8(Ctx);
505 Info.Flags = readVaruint32(Ctx);
506 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
509 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
510 Info.ElementIndex = readVaruint32(Ctx);
511 if (!isValidFunctionIndex(Info.ElementIndex) ||
512 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
513 return make_error<GenericBinaryError>("invalid function symbol index",
514 object_error::parse_failed);
516 Info.Name = readString(Ctx);
517 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
518 Signature = &Signatures[FunctionTypes[FuncIndex]];
519 wasm::WasmFunction &Function = Functions[FuncIndex];
520 if (Function.SymbolName.empty())
521 Function.SymbolName = Info.Name;
523 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
524 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
525 Info.Name = readString(Ctx);
526 Info.ImportName = Import.Field;
528 Info.Name = Import.Field;
530 Signature = &Signatures[Import.SigIndex];
531 if (!Import.Module.empty()) {
532 Info.ImportModule = Import.Module;
537 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
538 Info.ElementIndex = readVaruint32(Ctx);
539 if (!isValidGlobalIndex(Info.ElementIndex) ||
540 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
541 return make_error<GenericBinaryError>("invalid global symbol index",
542 object_error::parse_failed);
543 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
544 wasm::WASM_SYMBOL_BINDING_WEAK)
545 return make_error<GenericBinaryError>("undefined weak global symbol",
546 object_error::parse_failed);
548 Info.Name = readString(Ctx);
549 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
550 wasm::WasmGlobal &Global = Globals[GlobalIndex];
551 GlobalType = &Global.Type;
552 if (Global.SymbolName.empty())
553 Global.SymbolName = Info.Name;
555 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
556 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
557 Info.Name = readString(Ctx);
558 Info.ImportName = Import.Field;
560 Info.Name = Import.Field;
562 GlobalType = &Import.Global;
563 Info.ImportName = Import.Field;
564 if (!Import.Module.empty()) {
565 Info.ImportModule = Import.Module;
570 case wasm::WASM_SYMBOL_TYPE_DATA:
571 Info.Name = readString(Ctx);
573 auto Index = readVaruint32(Ctx);
574 if (Index >= DataSegments.size())
575 return make_error<GenericBinaryError>("invalid data symbol index",
576 object_error::parse_failed);
577 auto Offset = readVaruint64(Ctx);
578 auto Size = readVaruint64(Ctx);
579 if (Offset + Size > DataSegments[Index].Data.Content.size())
580 return make_error<GenericBinaryError>("invalid data symbol offset",
581 object_error::parse_failed);
582 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
586 case wasm::WASM_SYMBOL_TYPE_SECTION: {
587 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
588 wasm::WASM_SYMBOL_BINDING_LOCAL)
589 return make_error<GenericBinaryError>(
590 "Section symbols must have local binding",
591 object_error::parse_failed);
592 Info.ElementIndex = readVaruint32(Ctx);
593 // Use somewhat unique section name as symbol name.
594 StringRef SectionName = Sections[Info.ElementIndex].Name;
595 Info.Name = SectionName;
599 case wasm::WASM_SYMBOL_TYPE_EVENT: {
600 Info.ElementIndex = readVaruint32(Ctx);
601 if (!isValidEventIndex(Info.ElementIndex) ||
602 IsDefined != isDefinedEventIndex(Info.ElementIndex))
603 return make_error<GenericBinaryError>("invalid event symbol index",
604 object_error::parse_failed);
605 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
606 wasm::WASM_SYMBOL_BINDING_WEAK)
607 return make_error<GenericBinaryError>("undefined weak global symbol",
608 object_error::parse_failed);
610 Info.Name = readString(Ctx);
611 unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
612 wasm::WasmEvent &Event = Events[EventIndex];
613 Signature = &Signatures[Event.Type.SigIndex];
614 EventType = &Event.Type;
615 if (Event.SymbolName.empty())
616 Event.SymbolName = Info.Name;
619 wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
620 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
621 Info.Name = readString(Ctx);
622 Info.ImportName = Import.Field;
624 Info.Name = Import.Field;
626 EventType = &Import.Event;
627 Signature = &Signatures[EventType->SigIndex];
628 if (!Import.Module.empty()) {
629 Info.ImportModule = Import.Module;
636 return make_error<GenericBinaryError>("Invalid symbol type",
637 object_error::parse_failed);
640 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
641 wasm::WASM_SYMBOL_BINDING_LOCAL &&
642 !SymbolNames.insert(Info.Name).second)
643 return make_error<GenericBinaryError>("Duplicate symbol name " +
645 object_error::parse_failed);
646 LinkingData.SymbolTable.emplace_back(Info);
647 Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, EventType,
649 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
652 return Error::success();
655 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
656 uint32_t ComdatCount = readVaruint32(Ctx);
657 StringSet<> ComdatSet;
658 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
659 StringRef Name = readString(Ctx);
660 if (Name.empty() || !ComdatSet.insert(Name).second)
661 return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " +
663 object_error::parse_failed);
664 LinkingData.Comdats.emplace_back(Name);
665 uint32_t Flags = readVaruint32(Ctx);
667 return make_error<GenericBinaryError>("Unsupported COMDAT flags",
668 object_error::parse_failed);
670 uint32_t EntryCount = readVaruint32(Ctx);
671 while (EntryCount--) {
672 unsigned Kind = readVaruint32(Ctx);
673 unsigned Index = readVaruint32(Ctx);
676 return make_error<GenericBinaryError>("Invalid COMDAT entry type",
677 object_error::parse_failed);
678 case wasm::WASM_COMDAT_DATA:
679 if (Index >= DataSegments.size())
680 return make_error<GenericBinaryError>(
681 "COMDAT data index out of range", object_error::parse_failed);
682 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
683 return make_error<GenericBinaryError>("Data segment in two COMDATs",
684 object_error::parse_failed);
685 DataSegments[Index].Data.Comdat = ComdatIndex;
687 case wasm::WASM_COMDAT_FUNCTION:
688 if (!isDefinedFunctionIndex(Index))
689 return make_error<GenericBinaryError>(
690 "COMDAT function index out of range", object_error::parse_failed);
691 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
692 return make_error<GenericBinaryError>("Function in two COMDATs",
693 object_error::parse_failed);
694 getDefinedFunction(Index).Comdat = ComdatIndex;
699 return Error::success();
702 Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
703 llvm::SmallSet<StringRef, 3> FieldsSeen;
704 uint32_t Fields = readVaruint32(Ctx);
705 for (size_t I = 0; I < Fields; ++I) {
706 StringRef FieldName = readString(Ctx);
707 if (!FieldsSeen.insert(FieldName).second)
708 return make_error<GenericBinaryError>(
709 "Producers section does not have unique fields",
710 object_error::parse_failed);
711 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
712 if (FieldName == "language") {
713 ProducerVec = &ProducerInfo.Languages;
714 } else if (FieldName == "processed-by") {
715 ProducerVec = &ProducerInfo.Tools;
716 } else if (FieldName == "sdk") {
717 ProducerVec = &ProducerInfo.SDKs;
719 return make_error<GenericBinaryError>(
720 "Producers section field is not named one of language, processed-by, "
722 object_error::parse_failed);
724 uint32_t ValueCount = readVaruint32(Ctx);
725 llvm::SmallSet<StringRef, 8> ProducersSeen;
726 for (size_t J = 0; J < ValueCount; ++J) {
727 StringRef Name = readString(Ctx);
728 StringRef Version = readString(Ctx);
729 if (!ProducersSeen.insert(Name).second) {
730 return make_error<GenericBinaryError>(
731 "Producers section contains repeated producer",
732 object_error::parse_failed);
734 ProducerVec->emplace_back(std::string(Name), std::string(Version));
737 if (Ctx.Ptr != Ctx.End)
738 return make_error<GenericBinaryError>("Producers section ended prematurely",
739 object_error::parse_failed);
740 return Error::success();
743 Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
744 llvm::SmallSet<std::string, 8> FeaturesSeen;
745 uint32_t FeatureCount = readVaruint32(Ctx);
746 for (size_t I = 0; I < FeatureCount; ++I) {
747 wasm::WasmFeatureEntry Feature;
748 Feature.Prefix = readUint8(Ctx);
749 switch (Feature.Prefix) {
750 case wasm::WASM_FEATURE_PREFIX_USED:
751 case wasm::WASM_FEATURE_PREFIX_REQUIRED:
752 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
755 return make_error<GenericBinaryError>("Unknown feature policy prefix",
756 object_error::parse_failed);
758 Feature.Name = std::string(readString(Ctx));
759 if (!FeaturesSeen.insert(Feature.Name).second)
760 return make_error<GenericBinaryError>(
761 "Target features section contains repeated feature \"" +
763 object_error::parse_failed);
764 TargetFeatures.push_back(Feature);
766 if (Ctx.Ptr != Ctx.End)
767 return make_error<GenericBinaryError>(
768 "Target features section ended prematurely",
769 object_error::parse_failed);
770 return Error::success();
773 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
774 uint32_t SectionIndex = readVaruint32(Ctx);
775 if (SectionIndex >= Sections.size())
776 return make_error<GenericBinaryError>("Invalid section index",
777 object_error::parse_failed);
778 WasmSection &Section = Sections[SectionIndex];
779 uint32_t RelocCount = readVaruint32(Ctx);
780 uint32_t EndOffset = Section.Content.size();
781 uint32_t PreviousOffset = 0;
782 while (RelocCount--) {
783 wasm::WasmRelocation Reloc = {};
784 Reloc.Type = readVaruint32(Ctx);
785 Reloc.Offset = readVaruint32(Ctx);
786 if (Reloc.Offset < PreviousOffset)
787 return make_error<GenericBinaryError>("Relocations not in offset order",
788 object_error::parse_failed);
789 PreviousOffset = Reloc.Offset;
790 Reloc.Index = readVaruint32(Ctx);
791 switch (Reloc.Type) {
792 case wasm::R_WASM_FUNCTION_INDEX_LEB:
793 case wasm::R_WASM_TABLE_INDEX_SLEB:
794 case wasm::R_WASM_TABLE_INDEX_I32:
795 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
796 if (!isValidFunctionSymbol(Reloc.Index))
797 return make_error<GenericBinaryError>("Bad relocation function index",
798 object_error::parse_failed);
800 case wasm::R_WASM_TYPE_INDEX_LEB:
801 if (Reloc.Index >= Signatures.size())
802 return make_error<GenericBinaryError>("Bad relocation type index",
803 object_error::parse_failed);
805 case wasm::R_WASM_GLOBAL_INDEX_LEB:
806 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
807 // symbols to refer to their GOT entries.
808 if (!isValidGlobalSymbol(Reloc.Index) &&
809 !isValidDataSymbol(Reloc.Index) &&
810 !isValidFunctionSymbol(Reloc.Index))
811 return make_error<GenericBinaryError>("Bad relocation global index",
812 object_error::parse_failed);
814 case wasm::R_WASM_GLOBAL_INDEX_I32:
815 if (!isValidGlobalSymbol(Reloc.Index))
816 return make_error<GenericBinaryError>("Bad relocation global index",
817 object_error::parse_failed);
819 case wasm::R_WASM_EVENT_INDEX_LEB:
820 if (!isValidEventSymbol(Reloc.Index))
821 return make_error<GenericBinaryError>("Bad relocation event index",
822 object_error::parse_failed);
824 case wasm::R_WASM_MEMORY_ADDR_LEB:
825 case wasm::R_WASM_MEMORY_ADDR_SLEB:
826 case wasm::R_WASM_MEMORY_ADDR_I32:
827 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
828 if (!isValidDataSymbol(Reloc.Index))
829 return make_error<GenericBinaryError>("Bad relocation data index",
830 object_error::parse_failed);
831 Reloc.Addend = readVarint32(Ctx);
833 case wasm::R_WASM_MEMORY_ADDR_LEB64:
834 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
835 case wasm::R_WASM_MEMORY_ADDR_I64:
836 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
837 if (!isValidDataSymbol(Reloc.Index))
838 return make_error<GenericBinaryError>("Bad relocation data index",
839 object_error::parse_failed);
840 Reloc.Addend = readVarint64(Ctx);
842 case wasm::R_WASM_FUNCTION_OFFSET_I32:
843 if (!isValidFunctionSymbol(Reloc.Index))
844 return make_error<GenericBinaryError>("Bad relocation function index",
845 object_error::parse_failed);
846 Reloc.Addend = readVarint32(Ctx);
848 case wasm::R_WASM_SECTION_OFFSET_I32:
849 if (!isValidSectionSymbol(Reloc.Index))
850 return make_error<GenericBinaryError>("Bad relocation section index",
851 object_error::parse_failed);
852 Reloc.Addend = readVarint32(Ctx);
855 return make_error<GenericBinaryError>("Bad relocation type: " +
857 object_error::parse_failed);
860 // Relocations must fit inside the section, and must appear in order. They
861 // also shouldn't overlap a function/element boundary, but we don't bother
864 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
865 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
866 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
868 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
869 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
870 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
871 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
872 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
874 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64)
876 if (Reloc.Offset + Size > EndOffset)
877 return make_error<GenericBinaryError>("Bad relocation offset",
878 object_error::parse_failed);
880 Section.Relocations.push_back(Reloc);
882 if (Ctx.Ptr != Ctx.End)
883 return make_error<GenericBinaryError>("Reloc section ended prematurely",
884 object_error::parse_failed);
885 return Error::success();
888 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
889 if (Sec.Name == "dylink") {
890 if (Error Err = parseDylinkSection(Ctx))
892 } else if (Sec.Name == "name") {
893 if (Error Err = parseNameSection(Ctx))
895 } else if (Sec.Name == "linking") {
896 if (Error Err = parseLinkingSection(Ctx))
898 } else if (Sec.Name == "producers") {
899 if (Error Err = parseProducersSection(Ctx))
901 } else if (Sec.Name == "target_features") {
902 if (Error Err = parseTargetFeaturesSection(Ctx))
904 } else if (Sec.Name.startswith("reloc.")) {
905 if (Error Err = parseRelocSection(Sec.Name, Ctx))
908 return Error::success();
911 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
912 uint32_t Count = readVaruint32(Ctx);
913 Signatures.reserve(Count);
915 wasm::WasmSignature Sig;
916 uint8_t Form = readUint8(Ctx);
917 if (Form != wasm::WASM_TYPE_FUNC) {
918 return make_error<GenericBinaryError>("Invalid signature type",
919 object_error::parse_failed);
921 uint32_t ParamCount = readVaruint32(Ctx);
922 Sig.Params.reserve(ParamCount);
923 while (ParamCount--) {
924 uint32_t ParamType = readUint8(Ctx);
925 Sig.Params.push_back(wasm::ValType(ParamType));
927 uint32_t ReturnCount = readVaruint32(Ctx);
928 while (ReturnCount--) {
929 uint32_t ReturnType = readUint8(Ctx);
930 Sig.Returns.push_back(wasm::ValType(ReturnType));
932 Signatures.push_back(std::move(Sig));
934 if (Ctx.Ptr != Ctx.End)
935 return make_error<GenericBinaryError>("Type section ended prematurely",
936 object_error::parse_failed);
937 return Error::success();
940 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
941 uint32_t Count = readVaruint32(Ctx);
942 Imports.reserve(Count);
943 for (uint32_t I = 0; I < Count; I++) {
945 Im.Module = readString(Ctx);
946 Im.Field = readString(Ctx);
947 Im.Kind = readUint8(Ctx);
949 case wasm::WASM_EXTERNAL_FUNCTION:
950 NumImportedFunctions++;
951 Im.SigIndex = readVaruint32(Ctx);
953 case wasm::WASM_EXTERNAL_GLOBAL:
954 NumImportedGlobals++;
955 Im.Global.Type = readUint8(Ctx);
956 Im.Global.Mutable = readVaruint1(Ctx);
958 case wasm::WASM_EXTERNAL_MEMORY:
959 Im.Memory = readLimits(Ctx);
961 case wasm::WASM_EXTERNAL_TABLE:
962 Im.Table = readTable(Ctx);
963 if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF)
964 return make_error<GenericBinaryError>("Invalid table element type",
965 object_error::parse_failed);
967 case wasm::WASM_EXTERNAL_EVENT:
969 Im.Event.Attribute = readVarint32(Ctx);
970 Im.Event.SigIndex = readVarint32(Ctx);
973 return make_error<GenericBinaryError>("Unexpected import kind",
974 object_error::parse_failed);
976 Imports.push_back(Im);
978 if (Ctx.Ptr != Ctx.End)
979 return make_error<GenericBinaryError>("Import section ended prematurely",
980 object_error::parse_failed);
981 return Error::success();
984 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
985 uint32_t Count = readVaruint32(Ctx);
986 FunctionTypes.reserve(Count);
987 Functions.resize(Count);
988 uint32_t NumTypes = Signatures.size();
990 uint32_t Type = readVaruint32(Ctx);
991 if (Type >= NumTypes)
992 return make_error<GenericBinaryError>("Invalid function type",
993 object_error::parse_failed);
994 FunctionTypes.push_back(Type);
996 if (Ctx.Ptr != Ctx.End)
997 return make_error<GenericBinaryError>("Function section ended prematurely",
998 object_error::parse_failed);
999 return Error::success();
1002 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1003 uint32_t Count = readVaruint32(Ctx);
1004 Tables.reserve(Count);
1006 Tables.push_back(readTable(Ctx));
1007 if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF) {
1008 return make_error<GenericBinaryError>("Invalid table element type",
1009 object_error::parse_failed);
1012 if (Ctx.Ptr != Ctx.End)
1013 return make_error<GenericBinaryError>("Table section ended prematurely",
1014 object_error::parse_failed);
1015 return Error::success();
1018 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1019 uint32_t Count = readVaruint32(Ctx);
1020 Memories.reserve(Count);
1022 Memories.push_back(readLimits(Ctx));
1024 if (Ctx.Ptr != Ctx.End)
1025 return make_error<GenericBinaryError>("Memory section ended prematurely",
1026 object_error::parse_failed);
1027 return Error::success();
1030 Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
1031 EventSection = Sections.size();
1032 uint32_t Count = readVarint32(Ctx);
1033 Events.reserve(Count);
1035 wasm::WasmEvent Event;
1036 Event.Index = NumImportedEvents + Events.size();
1037 Event.Type.Attribute = readVaruint32(Ctx);
1038 Event.Type.SigIndex = readVarint32(Ctx);
1039 Events.push_back(Event);
1042 if (Ctx.Ptr != Ctx.End)
1043 return make_error<GenericBinaryError>("Event section ended prematurely",
1044 object_error::parse_failed);
1045 return Error::success();
1048 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1049 GlobalSection = Sections.size();
1050 uint32_t Count = readVaruint32(Ctx);
1051 Globals.reserve(Count);
1053 wasm::WasmGlobal Global;
1054 Global.Index = NumImportedGlobals + Globals.size();
1055 Global.Type.Type = readUint8(Ctx);
1056 Global.Type.Mutable = readVaruint1(Ctx);
1057 if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1059 Globals.push_back(Global);
1061 if (Ctx.Ptr != Ctx.End)
1062 return make_error<GenericBinaryError>("Global section ended prematurely",
1063 object_error::parse_failed);
1064 return Error::success();
1067 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1068 uint32_t Count = readVaruint32(Ctx);
1069 Exports.reserve(Count);
1070 for (uint32_t I = 0; I < Count; I++) {
1071 wasm::WasmExport Ex;
1072 Ex.Name = readString(Ctx);
1073 Ex.Kind = readUint8(Ctx);
1074 Ex.Index = readVaruint32(Ctx);
1076 case wasm::WASM_EXTERNAL_FUNCTION:
1078 if (!isDefinedFunctionIndex(Ex.Index))
1079 return make_error<GenericBinaryError>("Invalid function export",
1080 object_error::parse_failed);
1081 getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1083 case wasm::WASM_EXTERNAL_GLOBAL:
1084 if (!isValidGlobalIndex(Ex.Index))
1085 return make_error<GenericBinaryError>("Invalid global export",
1086 object_error::parse_failed);
1088 case wasm::WASM_EXTERNAL_EVENT:
1089 if (!isValidEventIndex(Ex.Index))
1090 return make_error<GenericBinaryError>("Invalid event export",
1091 object_error::parse_failed);
1093 case wasm::WASM_EXTERNAL_MEMORY:
1094 case wasm::WASM_EXTERNAL_TABLE:
1097 return make_error<GenericBinaryError>("Unexpected export kind",
1098 object_error::parse_failed);
1100 Exports.push_back(Ex);
1102 if (Ctx.Ptr != Ctx.End)
1103 return make_error<GenericBinaryError>("Export section ended prematurely",
1104 object_error::parse_failed);
1105 return Error::success();
1108 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1109 return Index < NumImportedFunctions + FunctionTypes.size();
1112 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1113 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1116 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1117 return Index < NumImportedGlobals + Globals.size();
1120 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1121 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1124 bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
1125 return Index < NumImportedEvents + Events.size();
1128 bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
1129 return Index >= NumImportedEvents && isValidEventIndex(Index);
1132 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1133 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1136 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1137 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1140 bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
1141 return Index < Symbols.size() && Symbols[Index].isTypeEvent();
1144 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1145 return Index < Symbols.size() && Symbols[Index].isTypeData();
1148 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1149 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1152 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1153 assert(isDefinedFunctionIndex(Index));
1154 return Functions[Index - NumImportedFunctions];
1157 const wasm::WasmFunction &
1158 WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1159 assert(isDefinedFunctionIndex(Index));
1160 return Functions[Index - NumImportedFunctions];
1163 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1164 assert(isDefinedGlobalIndex(Index));
1165 return Globals[Index - NumImportedGlobals];
1168 wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
1169 assert(isDefinedEventIndex(Index));
1170 return Events[Index - NumImportedEvents];
1173 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1174 StartFunction = readVaruint32(Ctx);
1175 if (!isValidFunctionIndex(StartFunction))
1176 return make_error<GenericBinaryError>("Invalid start function",
1177 object_error::parse_failed);
1178 return Error::success();
1181 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1182 SeenCodeSection = true;
1183 CodeSection = Sections.size();
1184 uint32_t FunctionCount = readVaruint32(Ctx);
1185 if (FunctionCount != FunctionTypes.size()) {
1186 return make_error<GenericBinaryError>("Invalid function count",
1187 object_error::parse_failed);
1190 for (uint32_t i = 0; i < FunctionCount; i++) {
1191 wasm::WasmFunction& Function = Functions[i];
1192 const uint8_t *FunctionStart = Ctx.Ptr;
1193 uint32_t Size = readVaruint32(Ctx);
1194 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1196 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1197 Function.Index = NumImportedFunctions + i;
1198 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1199 Function.Size = FunctionEnd - FunctionStart;
1201 uint32_t NumLocalDecls = readVaruint32(Ctx);
1202 Function.Locals.reserve(NumLocalDecls);
1203 while (NumLocalDecls--) {
1204 wasm::WasmLocalDecl Decl;
1205 Decl.Count = readVaruint32(Ctx);
1206 Decl.Type = readUint8(Ctx);
1207 Function.Locals.push_back(Decl);
1210 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1211 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1212 // This will be set later when reading in the linking metadata section.
1213 Function.Comdat = UINT32_MAX;
1214 Ctx.Ptr += BodySize;
1215 assert(Ctx.Ptr == FunctionEnd);
1217 if (Ctx.Ptr != Ctx.End)
1218 return make_error<GenericBinaryError>("Code section ended prematurely",
1219 object_error::parse_failed);
1220 return Error::success();
1223 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1224 uint32_t Count = readVaruint32(Ctx);
1225 ElemSegments.reserve(Count);
1227 wasm::WasmElemSegment Segment;
1228 Segment.TableIndex = readVaruint32(Ctx);
1229 if (Segment.TableIndex != 0) {
1230 return make_error<GenericBinaryError>("Invalid TableIndex",
1231 object_error::parse_failed);
1233 if (Error Err = readInitExpr(Segment.Offset, Ctx))
1235 uint32_t NumElems = readVaruint32(Ctx);
1236 while (NumElems--) {
1237 Segment.Functions.push_back(readVaruint32(Ctx));
1239 ElemSegments.push_back(Segment);
1241 if (Ctx.Ptr != Ctx.End)
1242 return make_error<GenericBinaryError>("Elem section ended prematurely",
1243 object_error::parse_failed);
1244 return Error::success();
1247 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1248 DataSection = Sections.size();
1249 uint32_t Count = readVaruint32(Ctx);
1250 if (DataCount && Count != DataCount.getValue())
1251 return make_error<GenericBinaryError>(
1252 "Number of data segments does not match DataCount section");
1253 DataSegments.reserve(Count);
1255 WasmSegment Segment;
1256 Segment.Data.InitFlags = readVaruint32(Ctx);
1257 Segment.Data.MemoryIndex = (Segment.Data.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
1258 ? readVaruint32(Ctx) : 0;
1259 if ((Segment.Data.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
1260 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1263 Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
1264 Segment.Data.Offset.Value.Int32 = 0;
1266 uint32_t Size = readVaruint32(Ctx);
1267 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1268 return make_error<GenericBinaryError>("Invalid segment size",
1269 object_error::parse_failed);
1270 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1271 // The rest of these Data fields are set later, when reading in the linking
1272 // metadata section.
1273 Segment.Data.Alignment = 0;
1274 Segment.Data.LinkerFlags = 0;
1275 Segment.Data.Comdat = UINT32_MAX;
1276 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1278 DataSegments.push_back(Segment);
1280 if (Ctx.Ptr != Ctx.End)
1281 return make_error<GenericBinaryError>("Data section ended prematurely",
1282 object_error::parse_failed);
1283 return Error::success();
1286 Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1287 DataCount = readVaruint32(Ctx);
1288 return Error::success();
1291 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1295 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1297 Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1298 uint32_t Result = SymbolRef::SF_None;
1299 const WasmSymbol &Sym = getWasmSymbol(Symb);
1301 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1302 if (Sym.isBindingWeak())
1303 Result |= SymbolRef::SF_Weak;
1304 if (!Sym.isBindingLocal())
1305 Result |= SymbolRef::SF_Global;
1307 Result |= SymbolRef::SF_Hidden;
1308 if (!Sym.isDefined())
1309 Result |= SymbolRef::SF_Undefined;
1310 if (Sym.isTypeFunction())
1311 Result |= SymbolRef::SF_Executable;
1315 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1317 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1318 Ref.d.b = 0; // Symbol index
1319 return BasicSymbolRef(Ref, this);
1322 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1324 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1325 Ref.d.b = Symbols.size(); // Symbol index
1326 return BasicSymbolRef(Ref, this);
1329 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1330 return Symbols[Symb.d.b];
1333 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1334 return getWasmSymbol(Symb.getRawDataRefImpl());
1337 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1338 return getWasmSymbol(Symb).Info.Name;
1341 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1342 auto &Sym = getWasmSymbol(Symb);
1343 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1344 isDefinedFunctionIndex(Sym.Info.ElementIndex))
1345 return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
1347 return getSymbolValue(Symb);
1350 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1351 switch (Sym.Info.Kind) {
1352 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1353 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1354 case wasm::WASM_SYMBOL_TYPE_EVENT:
1355 return Sym.Info.ElementIndex;
1356 case wasm::WASM_SYMBOL_TYPE_DATA: {
1357 // The value of a data symbol is the segment offset, plus the symbol
1358 // offset within the segment.
1359 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1360 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1361 if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1362 return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
1363 } else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1364 return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
1366 llvm_unreachable("unknown init expr opcode");
1369 case wasm::WASM_SYMBOL_TYPE_SECTION:
1372 llvm_unreachable("invalid symbol type");
1375 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1376 return getWasmSymbolValue(getWasmSymbol(Symb));
1379 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1380 llvm_unreachable("not yet implemented");
1384 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1385 llvm_unreachable("not yet implemented");
1389 Expected<SymbolRef::Type>
1390 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1391 const WasmSymbol &Sym = getWasmSymbol(Symb);
1393 switch (Sym.Info.Kind) {
1394 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1395 return SymbolRef::ST_Function;
1396 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1397 return SymbolRef::ST_Other;
1398 case wasm::WASM_SYMBOL_TYPE_DATA:
1399 return SymbolRef::ST_Data;
1400 case wasm::WASM_SYMBOL_TYPE_SECTION:
1401 return SymbolRef::ST_Debug;
1402 case wasm::WASM_SYMBOL_TYPE_EVENT:
1403 return SymbolRef::ST_Other;
1406 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1407 return SymbolRef::ST_Other;
1410 Expected<section_iterator>
1411 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1412 const WasmSymbol &Sym = getWasmSymbol(Symb);
1413 if (Sym.isUndefined())
1414 return section_end();
1417 Ref.d.a = getSymbolSectionIdImpl(Sym);
1418 return section_iterator(SectionRef(Ref, this));
1421 uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1422 const WasmSymbol &Sym = getWasmSymbol(Symb);
1423 return getSymbolSectionIdImpl(Sym);
1426 uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1427 switch (Sym.Info.Kind) {
1428 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1430 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1431 return GlobalSection;
1432 case wasm::WASM_SYMBOL_TYPE_DATA:
1434 case wasm::WASM_SYMBOL_TYPE_SECTION:
1435 return Sym.Info.ElementIndex;
1436 case wasm::WASM_SYMBOL_TYPE_EVENT:
1437 return EventSection;
1439 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1443 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1445 Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1446 const WasmSection &S = Sections[Sec.d.a];
1448 case wasm::WASM_SEC_##X: \
1464 case wasm::WASM_SEC_CUSTOM:
1467 return createStringError(object_error::invalid_section_index, "");
1472 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1474 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1478 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1479 const WasmSection &S = Sections[Sec.d.a];
1480 return S.Content.size();
1483 Expected<ArrayRef<uint8_t>>
1484 WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1485 const WasmSection &S = Sections[Sec.d.a];
1486 // This will never fail since wasm sections can never be empty (user-sections
1487 // must have a name and non-user sections each have a defined structure).
1491 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1495 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1499 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1500 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1503 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1504 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1507 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1509 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1511 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1512 DataRefImpl RelocRef;
1513 RelocRef.d.a = Ref.d.a;
1515 return relocation_iterator(RelocationRef(RelocRef, this));
1518 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1519 const WasmSection &Sec = getWasmSection(Ref);
1520 DataRefImpl RelocRef;
1521 RelocRef.d.a = Ref.d.a;
1522 RelocRef.d.b = Sec.Relocations.size();
1523 return relocation_iterator(RelocationRef(RelocRef, this));
1526 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1528 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1529 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1533 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1534 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1535 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
1536 return symbol_end();
1539 Sym.d.b = Rel.Index;
1540 return symbol_iterator(SymbolRef(Sym, this));
1543 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1544 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1548 void WasmObjectFile::getRelocationTypeName(
1549 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1550 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1551 StringRef Res = "Unknown";
1553 #define WASM_RELOC(name, value) \
1559 #include "llvm/BinaryFormat/WasmRelocs.def"
1564 Result.append(Res.begin(), Res.end());
1567 section_iterator WasmObjectFile::section_begin() const {
1570 return section_iterator(SectionRef(Ref, this));
1573 section_iterator WasmObjectFile::section_end() const {
1575 Ref.d.a = Sections.size();
1576 return section_iterator(SectionRef(Ref, this));
1579 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1581 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1583 Triple::ArchType WasmObjectFile::getArch() const { return Triple::wasm32; }
1585 SubtargetFeatures WasmObjectFile::getFeatures() const {
1586 return SubtargetFeatures();
1589 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1591 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1593 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1594 assert(Ref.d.a < Sections.size());
1595 return Sections[Ref.d.a];
1599 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1600 return getWasmSection(Section.getRawDataRefImpl());
1603 const wasm::WasmRelocation &
1604 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1605 return getWasmRelocation(Ref.getRawDataRefImpl());
1608 const wasm::WasmRelocation &
1609 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1610 assert(Ref.d.a < Sections.size());
1611 const WasmSection &Sec = Sections[Ref.d.a];
1612 assert(Ref.d.b < Sec.Relocations.size());
1613 return Sec.Relocations[Ref.d.b];
1616 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1617 StringRef CustomSectionName) {
1619 case wasm::WASM_SEC_CUSTOM:
1620 return StringSwitch<unsigned>(CustomSectionName)
1621 .Case("dylink", WASM_SEC_ORDER_DYLINK)
1622 .Case("linking", WASM_SEC_ORDER_LINKING)
1623 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1624 .Case("name", WASM_SEC_ORDER_NAME)
1625 .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1626 .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
1627 .Default(WASM_SEC_ORDER_NONE);
1628 case wasm::WASM_SEC_TYPE:
1629 return WASM_SEC_ORDER_TYPE;
1630 case wasm::WASM_SEC_IMPORT:
1631 return WASM_SEC_ORDER_IMPORT;
1632 case wasm::WASM_SEC_FUNCTION:
1633 return WASM_SEC_ORDER_FUNCTION;
1634 case wasm::WASM_SEC_TABLE:
1635 return WASM_SEC_ORDER_TABLE;
1636 case wasm::WASM_SEC_MEMORY:
1637 return WASM_SEC_ORDER_MEMORY;
1638 case wasm::WASM_SEC_GLOBAL:
1639 return WASM_SEC_ORDER_GLOBAL;
1640 case wasm::WASM_SEC_EXPORT:
1641 return WASM_SEC_ORDER_EXPORT;
1642 case wasm::WASM_SEC_START:
1643 return WASM_SEC_ORDER_START;
1644 case wasm::WASM_SEC_ELEM:
1645 return WASM_SEC_ORDER_ELEM;
1646 case wasm::WASM_SEC_CODE:
1647 return WASM_SEC_ORDER_CODE;
1648 case wasm::WASM_SEC_DATA:
1649 return WASM_SEC_ORDER_DATA;
1650 case wasm::WASM_SEC_DATACOUNT:
1651 return WASM_SEC_ORDER_DATACOUNT;
1652 case wasm::WASM_SEC_EVENT:
1653 return WASM_SEC_ORDER_EVENT;
1655 return WASM_SEC_ORDER_NONE;
1659 // Represents the edges in a directed graph where any node B reachable from node
1660 // A is not allowed to appear before A in the section ordering, but may appear
1662 int WasmSectionOrderChecker::DisallowedPredecessors
1663 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
1664 // WASM_SEC_ORDER_NONE
1666 // WASM_SEC_ORDER_TYPE
1667 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
1668 // WASM_SEC_ORDER_IMPORT
1669 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
1670 // WASM_SEC_ORDER_FUNCTION
1671 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
1672 // WASM_SEC_ORDER_TABLE
1673 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
1674 // WASM_SEC_ORDER_MEMORY
1675 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_EVENT},
1676 // WASM_SEC_ORDER_EVENT
1677 {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_GLOBAL},
1678 // WASM_SEC_ORDER_GLOBAL
1679 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
1680 // WASM_SEC_ORDER_EXPORT
1681 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
1682 // WASM_SEC_ORDER_START
1683 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
1684 // WASM_SEC_ORDER_ELEM
1685 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
1686 // WASM_SEC_ORDER_DATACOUNT
1687 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
1688 // WASM_SEC_ORDER_CODE
1689 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
1690 // WASM_SEC_ORDER_DATA
1691 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
1694 // WASM_SEC_ORDER_DYLINK
1695 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
1696 // WASM_SEC_ORDER_LINKING
1697 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
1698 // WASM_SEC_ORDER_RELOC (can be repeated)
1700 // WASM_SEC_ORDER_NAME
1701 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
1702 // WASM_SEC_ORDER_PRODUCERS
1703 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
1704 // WASM_SEC_ORDER_TARGET_FEATURES
1705 {WASM_SEC_ORDER_TARGET_FEATURES}};
1707 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1708 StringRef CustomSectionName) {
1709 int Order = getSectionOrder(ID, CustomSectionName);
1710 if (Order == WASM_SEC_ORDER_NONE)
1713 // Disallowed predecessors we need to check for
1714 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
1716 // Keep track of completed checks to avoid repeating work
1717 bool Checked[WASM_NUM_SEC_ORDERS] = {};
1721 // Add new disallowed predecessors to work list
1722 for (size_t I = 0;; ++I) {
1723 int Next = DisallowedPredecessors[Curr][I];
1724 if (Next == WASM_SEC_ORDER_NONE)
1728 WorkList.push_back(Next);
1729 Checked[Next] = true;
1732 if (WorkList.empty())
1735 // Consider next disallowed predecessor
1736 Curr = WorkList.pop_back_val();
1741 // Have not seen any disallowed predecessors