1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/DenseSet.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/BinaryFormat/Wasm.h"
17 #include "llvm/MC/SubtargetFeature.h"
18 #include "llvm/Object/Binary.h"
19 #include "llvm/Object/Error.h"
20 #include "llvm/Object/ObjectFile.h"
21 #include "llvm/Object/SymbolicFile.h"
22 #include "llvm/Object/Wasm.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include "llvm/Support/LEB128.h"
31 #include <system_error>
33 #define DEBUG_TYPE "wasm-object"
36 using namespace object;
38 void WasmSymbol::print(raw_ostream &Out) const {
39 Out << "Name=" << Info.Name
40 << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind))
41 << ", Flags=" << Info.Flags;
43 Out << ", ElemIndex=" << Info.ElementIndex;
44 } else if (isDefined()) {
45 Out << ", Segment=" << Info.DataRef.Segment;
46 Out << ", Offset=" << Info.DataRef.Offset;
47 Out << ", Size=" << Info.DataRef.Size;
51 Expected<std::unique_ptr<WasmObjectFile>>
52 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
53 Error Err = Error::success();
54 auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
56 return std::move(Err);
58 return std::move(ObjectFile);
61 #define VARINT7_MAX ((1<<7)-1)
62 #define VARINT7_MIN (-(1<<7))
63 #define VARUINT7_MAX (1<<7)
64 #define VARUINT1_MAX (1)
66 static uint8_t readUint8(const uint8_t *&Ptr) { return *Ptr++; }
68 static uint32_t readUint32(const uint8_t *&Ptr) {
69 uint32_t Result = support::endian::read32le(Ptr);
70 Ptr += sizeof(Result);
74 static int32_t readFloat32(const uint8_t *&Ptr) {
76 memcpy(&Result, Ptr, sizeof(Result));
77 Ptr += sizeof(Result);
81 static int64_t readFloat64(const uint8_t *&Ptr) {
83 memcpy(&Result, Ptr, sizeof(Result));
84 Ptr += sizeof(Result);
88 static uint64_t readULEB128(const uint8_t *&Ptr) {
90 uint64_t Result = decodeULEB128(Ptr, &Count);
95 static StringRef readString(const uint8_t *&Ptr) {
96 uint32_t StringLen = readULEB128(Ptr);
97 StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen);
102 static int64_t readLEB128(const uint8_t *&Ptr) {
104 uint64_t Result = decodeSLEB128(Ptr, &Count);
109 static uint8_t readVaruint1(const uint8_t *&Ptr) {
110 int64_t result = readLEB128(Ptr);
111 assert(result <= VARUINT1_MAX && result >= 0);
115 static int32_t readVarint32(const uint8_t *&Ptr) {
116 int64_t result = readLEB128(Ptr);
117 assert(result <= INT32_MAX && result >= INT32_MIN);
121 static uint32_t readVaruint32(const uint8_t *&Ptr) {
122 uint64_t result = readULEB128(Ptr);
123 assert(result <= UINT32_MAX);
127 static int64_t readVarint64(const uint8_t *&Ptr) {
128 return readLEB128(Ptr);
131 static uint8_t readOpcode(const uint8_t *&Ptr) {
132 return readUint8(Ptr);
135 static Error readInitExpr(wasm::WasmInitExpr &Expr, const uint8_t *&Ptr) {
136 Expr.Opcode = readOpcode(Ptr);
138 switch (Expr.Opcode) {
139 case wasm::WASM_OPCODE_I32_CONST:
140 Expr.Value.Int32 = readVarint32(Ptr);
142 case wasm::WASM_OPCODE_I64_CONST:
143 Expr.Value.Int64 = readVarint64(Ptr);
145 case wasm::WASM_OPCODE_F32_CONST:
146 Expr.Value.Float32 = readFloat32(Ptr);
148 case wasm::WASM_OPCODE_F64_CONST:
149 Expr.Value.Float64 = readFloat64(Ptr);
151 case wasm::WASM_OPCODE_GET_GLOBAL:
152 Expr.Value.Global = readULEB128(Ptr);
155 return make_error<GenericBinaryError>("Invalid opcode in init_expr",
156 object_error::parse_failed);
159 uint8_t EndOpcode = readOpcode(Ptr);
160 if (EndOpcode != wasm::WASM_OPCODE_END) {
161 return make_error<GenericBinaryError>("Invalid init_expr",
162 object_error::parse_failed);
164 return Error::success();
167 static wasm::WasmLimits readLimits(const uint8_t *&Ptr) {
168 wasm::WasmLimits Result;
169 Result.Flags = readVaruint1(Ptr);
170 Result.Initial = readVaruint32(Ptr);
171 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
172 Result.Maximum = readVaruint32(Ptr);
176 static wasm::WasmTable readTable(const uint8_t *&Ptr) {
177 wasm::WasmTable Table;
178 Table.ElemType = readUint8(Ptr);
179 Table.Limits = readLimits(Ptr);
183 static Error readSection(WasmSection &Section, const uint8_t *&Ptr,
184 const uint8_t *Start, const uint8_t *Eof) {
185 Section.Offset = Ptr - Start;
186 Section.Type = readUint8(Ptr);
187 uint32_t Size = readVaruint32(Ptr);
189 return make_error<StringError>("Zero length section",
190 object_error::parse_failed);
191 if (Ptr + Size > Eof)
192 return make_error<StringError>("Section too large",
193 object_error::parse_failed);
194 if (Section.Type == wasm::WASM_SEC_CUSTOM) {
195 const uint8_t *NameStart = Ptr;
196 Section.Name = readString(Ptr);
197 Size -= Ptr - NameStart;
199 Section.Content = ArrayRef<uint8_t>(Ptr, Size);
201 return Error::success();
204 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
205 : ObjectFile(Binary::ID_Wasm, Buffer) {
206 ErrorAsOutParameter ErrAsOutParam(&Err);
207 Header.Magic = getData().substr(0, 4);
208 if (Header.Magic != StringRef("\0asm", 4)) {
209 Err = make_error<StringError>("Bad magic number",
210 object_error::parse_failed);
214 const uint8_t *Eof = getPtr(getData().size());
215 const uint8_t *Ptr = getPtr(4);
218 Err = make_error<StringError>("Missing version number",
219 object_error::parse_failed);
223 Header.Version = readUint32(Ptr);
224 if (Header.Version != wasm::WasmVersion) {
225 Err = make_error<StringError>("Bad version number",
226 object_error::parse_failed);
232 if ((Err = readSection(Sec, Ptr, getPtr(0), Eof)))
234 if ((Err = parseSection(Sec)))
237 Sections.push_back(Sec);
241 Error WasmObjectFile::parseSection(WasmSection &Sec) {
242 const uint8_t* Start = Sec.Content.data();
243 const uint8_t* End = Start + Sec.Content.size();
245 case wasm::WASM_SEC_CUSTOM:
246 return parseCustomSection(Sec, Start, End);
247 case wasm::WASM_SEC_TYPE:
248 return parseTypeSection(Start, End);
249 case wasm::WASM_SEC_IMPORT:
250 return parseImportSection(Start, End);
251 case wasm::WASM_SEC_FUNCTION:
252 return parseFunctionSection(Start, End);
253 case wasm::WASM_SEC_TABLE:
254 return parseTableSection(Start, End);
255 case wasm::WASM_SEC_MEMORY:
256 return parseMemorySection(Start, End);
257 case wasm::WASM_SEC_GLOBAL:
258 return parseGlobalSection(Start, End);
259 case wasm::WASM_SEC_EXPORT:
260 return parseExportSection(Start, End);
261 case wasm::WASM_SEC_START:
262 return parseStartSection(Start, End);
263 case wasm::WASM_SEC_ELEM:
264 return parseElemSection(Start, End);
265 case wasm::WASM_SEC_CODE:
266 return parseCodeSection(Start, End);
267 case wasm::WASM_SEC_DATA:
268 return parseDataSection(Start, End);
270 return make_error<GenericBinaryError>("Bad section type",
271 object_error::parse_failed);
275 Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) {
276 llvm::DenseSet<uint64_t> Seen;
277 if (Functions.size() != FunctionTypes.size()) {
278 return make_error<GenericBinaryError>("Names must come after code section",
279 object_error::parse_failed);
283 uint8_t Type = readUint8(Ptr);
284 uint32_t Size = readVaruint32(Ptr);
285 const uint8_t *SubSectionEnd = Ptr + Size;
287 case wasm::WASM_NAMES_FUNCTION: {
288 uint32_t Count = readVaruint32(Ptr);
290 uint32_t Index = readVaruint32(Ptr);
291 if (!Seen.insert(Index).second)
292 return make_error<GenericBinaryError>("Function named more than once",
293 object_error::parse_failed);
294 StringRef Name = readString(Ptr);
295 if (!isValidFunctionIndex(Index) || Name.empty())
296 return make_error<GenericBinaryError>("Invalid name entry",
297 object_error::parse_failed);
298 DebugNames.push_back(wasm::WasmFunctionName{Index, Name});
299 if (isDefinedFunctionIndex(Index))
300 getDefinedFunction(Index).DebugName = Name;
304 // Ignore local names for now
305 case wasm::WASM_NAMES_LOCAL:
310 if (Ptr != SubSectionEnd)
311 return make_error<GenericBinaryError>("Name sub-section ended prematurely",
312 object_error::parse_failed);
316 return make_error<GenericBinaryError>("Name section ended prematurely",
317 object_error::parse_failed);
318 return Error::success();
321 Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
322 const uint8_t *End) {
323 HasLinkingSection = true;
324 if (Functions.size() != FunctionTypes.size()) {
325 return make_error<GenericBinaryError>(
326 "Linking data must come after code section", object_error::parse_failed);
329 LinkingData.Version = readVaruint32(Ptr);
330 if (LinkingData.Version != wasm::WasmMetadataVersion) {
331 return make_error<GenericBinaryError>(
332 "Unexpected metadata version: " + Twine(LinkingData.Version) +
333 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
334 object_error::parse_failed);
338 uint8_t Type = readUint8(Ptr);
339 uint32_t Size = readVaruint32(Ptr);
340 const uint8_t *SubSectionEnd = Ptr + Size;
342 case wasm::WASM_SYMBOL_TABLE:
343 if (Error Err = parseLinkingSectionSymtab(Ptr, SubSectionEnd))
346 case wasm::WASM_SEGMENT_INFO: {
347 uint32_t Count = readVaruint32(Ptr);
348 if (Count > DataSegments.size())
349 return make_error<GenericBinaryError>("Too many segment names",
350 object_error::parse_failed);
351 for (uint32_t i = 0; i < Count; i++) {
352 DataSegments[i].Data.Name = readString(Ptr);
353 DataSegments[i].Data.Alignment = readVaruint32(Ptr);
354 DataSegments[i].Data.Flags = readVaruint32(Ptr);
358 case wasm::WASM_INIT_FUNCS: {
359 uint32_t Count = readVaruint32(Ptr);
360 LinkingData.InitFunctions.reserve(Count);
361 for (uint32_t i = 0; i < Count; i++) {
362 wasm::WasmInitFunc Init;
363 Init.Priority = readVaruint32(Ptr);
364 Init.Symbol = readVaruint32(Ptr);
365 if (!isValidFunctionSymbol(Init.Symbol))
366 return make_error<GenericBinaryError>("Invalid function symbol: " +
368 object_error::parse_failed);
369 LinkingData.InitFunctions.emplace_back(Init);
373 case wasm::WASM_COMDAT_INFO:
374 if (Error Err = parseLinkingSectionComdat(Ptr, SubSectionEnd))
381 if (Ptr != SubSectionEnd)
382 return make_error<GenericBinaryError>(
383 "Linking sub-section ended prematurely", object_error::parse_failed);
386 return make_error<GenericBinaryError>("Linking section ended prematurely",
387 object_error::parse_failed);
388 return Error::success();
391 Error WasmObjectFile::parseLinkingSectionSymtab(const uint8_t *&Ptr,
392 const uint8_t *End) {
393 uint32_t Count = readVaruint32(Ptr);
394 LinkingData.SymbolTable.reserve(Count);
395 Symbols.reserve(Count);
396 StringSet<> SymbolNames;
398 std::vector<wasm::WasmImport *> ImportedGlobals;
399 std::vector<wasm::WasmImport *> ImportedFunctions;
400 ImportedGlobals.reserve(Imports.size());
401 ImportedFunctions.reserve(Imports.size());
402 for (auto &I : Imports) {
403 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
404 ImportedFunctions.emplace_back(&I);
405 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
406 ImportedGlobals.emplace_back(&I);
410 wasm::WasmSymbolInfo Info;
411 const wasm::WasmSignature *FunctionType = nullptr;
412 const wasm::WasmGlobalType *GlobalType = nullptr;
414 Info.Kind = readUint8(Ptr);
415 Info.Flags = readVaruint32(Ptr);
416 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
419 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
420 Info.ElementIndex = readVaruint32(Ptr);
421 if (!isValidFunctionIndex(Info.ElementIndex) ||
422 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
423 return make_error<GenericBinaryError>("invalid function symbol index",
424 object_error::parse_failed);
426 Info.Name = readString(Ptr);
427 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
428 FunctionType = &Signatures[FunctionTypes[FuncIndex]];
429 wasm::WasmFunction &Function = Functions[FuncIndex];
430 if (Function.SymbolName.empty())
431 Function.SymbolName = Info.Name;
433 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
434 FunctionType = &Signatures[Import.SigIndex];
435 Info.Name = Import.Field;
436 Info.Module = Import.Module;
440 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
441 Info.ElementIndex = readVaruint32(Ptr);
442 if (!isValidGlobalIndex(Info.ElementIndex) ||
443 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
444 return make_error<GenericBinaryError>("invalid global symbol index",
445 object_error::parse_failed);
447 (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
448 wasm::WASM_SYMBOL_BINDING_WEAK)
449 return make_error<GenericBinaryError>("undefined weak global symbol",
450 object_error::parse_failed);
452 Info.Name = readString(Ptr);
453 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
454 wasm::WasmGlobal &Global = Globals[GlobalIndex];
455 GlobalType = &Global.Type;
456 if (Global.SymbolName.empty())
457 Global.SymbolName = Info.Name;
459 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
460 Info.Name = Import.Field;
461 GlobalType = &Import.Global;
465 case wasm::WASM_SYMBOL_TYPE_DATA:
466 Info.Name = readString(Ptr);
468 uint32_t Index = readVaruint32(Ptr);
469 if (Index >= DataSegments.size())
470 return make_error<GenericBinaryError>("invalid data symbol index",
471 object_error::parse_failed);
472 uint32_t Offset = readVaruint32(Ptr);
473 uint32_t Size = readVaruint32(Ptr);
474 if (Offset + Size > DataSegments[Index].Data.Content.size())
475 return make_error<GenericBinaryError>("invalid data symbol offset",
476 object_error::parse_failed);
477 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
481 case wasm::WASM_SYMBOL_TYPE_SECTION: {
482 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
483 wasm::WASM_SYMBOL_BINDING_LOCAL)
484 return make_error<GenericBinaryError>(
485 "Section symbols must have local binding",
486 object_error::parse_failed);
487 Info.ElementIndex = readVaruint32(Ptr);
488 // Use somewhat unique section name as symbol name.
489 StringRef SectionName = Sections[Info.ElementIndex].Name;
490 Info.Name = SectionName;
495 return make_error<GenericBinaryError>("Invalid symbol type",
496 object_error::parse_failed);
499 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
500 wasm::WASM_SYMBOL_BINDING_LOCAL &&
501 !SymbolNames.insert(Info.Name).second)
502 return make_error<GenericBinaryError>("Duplicate symbol name " +
504 object_error::parse_failed);
505 LinkingData.SymbolTable.emplace_back(Info);
506 Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType,
508 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
511 return Error::success();
514 Error WasmObjectFile::parseLinkingSectionComdat(const uint8_t *&Ptr,
517 uint32_t ComdatCount = readVaruint32(Ptr);
518 StringSet<> ComdatSet;
519 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
520 StringRef Name = readString(Ptr);
521 if (Name.empty() || !ComdatSet.insert(Name).second)
522 return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " + Twine(Name),
523 object_error::parse_failed);
524 LinkingData.Comdats.emplace_back(Name);
525 uint32_t Flags = readVaruint32(Ptr);
527 return make_error<GenericBinaryError>("Unsupported COMDAT flags",
528 object_error::parse_failed);
530 uint32_t EntryCount = readVaruint32(Ptr);
531 while (EntryCount--) {
532 unsigned Kind = readVaruint32(Ptr);
533 unsigned Index = readVaruint32(Ptr);
536 return make_error<GenericBinaryError>("Invalid COMDAT entry type",
537 object_error::parse_failed);
538 case wasm::WASM_COMDAT_DATA:
539 if (Index >= DataSegments.size())
540 return make_error<GenericBinaryError>("COMDAT data index out of range",
541 object_error::parse_failed);
542 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
543 return make_error<GenericBinaryError>("Data segment in two COMDATs",
544 object_error::parse_failed);
545 DataSegments[Index].Data.Comdat = ComdatIndex;
547 case wasm::WASM_COMDAT_FUNCTION:
548 if (!isDefinedFunctionIndex(Index))
549 return make_error<GenericBinaryError>("COMDAT function index out of range",
550 object_error::parse_failed);
551 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
552 return make_error<GenericBinaryError>("Function in two COMDATs",
553 object_error::parse_failed);
554 getDefinedFunction(Index).Comdat = ComdatIndex;
559 return Error::success();
562 Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
563 const uint8_t *End) {
564 uint32_t SectionIndex = readVaruint32(Ptr);
565 if (SectionIndex >= Sections.size())
566 return make_error<GenericBinaryError>("Invalid section index",
567 object_error::parse_failed);
568 WasmSection& Section = Sections[SectionIndex];
569 uint32_t RelocCount = readVaruint32(Ptr);
570 uint32_t EndOffset = Section.Content.size();
571 while (RelocCount--) {
572 wasm::WasmRelocation Reloc = {};
573 Reloc.Type = readVaruint32(Ptr);
574 Reloc.Offset = readVaruint32(Ptr);
575 Reloc.Index = readVaruint32(Ptr);
576 switch (Reloc.Type) {
577 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
578 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
579 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
580 if (!isValidFunctionSymbol(Reloc.Index))
581 return make_error<GenericBinaryError>("Bad relocation function index",
582 object_error::parse_failed);
584 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
585 if (Reloc.Index >= Signatures.size())
586 return make_error<GenericBinaryError>("Bad relocation type index",
587 object_error::parse_failed);
589 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
590 if (!isValidGlobalSymbol(Reloc.Index))
591 return make_error<GenericBinaryError>("Bad relocation global index",
592 object_error::parse_failed);
594 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
595 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
596 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
597 if (!isValidDataSymbol(Reloc.Index))
598 return make_error<GenericBinaryError>("Bad relocation data index",
599 object_error::parse_failed);
600 Reloc.Addend = readVarint32(Ptr);
602 case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
603 if (!isValidFunctionSymbol(Reloc.Index))
604 return make_error<GenericBinaryError>("Bad relocation function index",
605 object_error::parse_failed);
606 Reloc.Addend = readVarint32(Ptr);
608 case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
609 if (!isValidSectionSymbol(Reloc.Index))
610 return make_error<GenericBinaryError>("Bad relocation section index",
611 object_error::parse_failed);
612 Reloc.Addend = readVarint32(Ptr);
615 return make_error<GenericBinaryError>("Bad relocation type: " +
617 object_error::parse_failed);
620 // Relocations must fit inside the section, and must appear in order. They
621 // also shouldn't overlap a function/element boundary, but we don't bother
624 if (Reloc.Type == wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 ||
625 Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32 ||
626 Reloc.Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32 ||
627 Reloc.Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32)
629 if (Reloc.Offset + Size > EndOffset)
630 return make_error<GenericBinaryError>("Bad relocation offset",
631 object_error::parse_failed);
633 Section.Relocations.push_back(Reloc);
636 return make_error<GenericBinaryError>("Reloc section ended prematurely",
637 object_error::parse_failed);
638 return Error::success();
641 Error WasmObjectFile::parseCustomSection(WasmSection &Sec,
642 const uint8_t *Ptr, const uint8_t *End) {
643 if (Sec.Name == "name") {
644 if (Error Err = parseNameSection(Ptr, End))
646 } else if (Sec.Name == "linking") {
647 if (Error Err = parseLinkingSection(Ptr, End))
649 } else if (Sec.Name.startswith("reloc.")) {
650 if (Error Err = parseRelocSection(Sec.Name, Ptr, End))
653 return Error::success();
656 Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) {
657 uint32_t Count = readVaruint32(Ptr);
658 Signatures.reserve(Count);
660 wasm::WasmSignature Sig;
661 Sig.ReturnType = wasm::WASM_TYPE_NORESULT;
662 uint8_t Form = readUint8(Ptr);
663 if (Form != wasm::WASM_TYPE_FUNC) {
664 return make_error<GenericBinaryError>("Invalid signature type",
665 object_error::parse_failed);
667 uint32_t ParamCount = readVaruint32(Ptr);
668 Sig.ParamTypes.reserve(ParamCount);
669 while (ParamCount--) {
670 uint32_t ParamType = readUint8(Ptr);
671 Sig.ParamTypes.push_back(ParamType);
673 uint32_t ReturnCount = readVaruint32(Ptr);
675 if (ReturnCount != 1) {
676 return make_error<GenericBinaryError>(
677 "Multiple return types not supported", object_error::parse_failed);
679 Sig.ReturnType = readUint8(Ptr);
681 Signatures.push_back(Sig);
684 return make_error<GenericBinaryError>("Type section ended prematurely",
685 object_error::parse_failed);
686 return Error::success();
689 Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) {
690 uint32_t Count = readVaruint32(Ptr);
691 Imports.reserve(Count);
692 for (uint32_t i = 0; i < Count; i++) {
694 Im.Module = readString(Ptr);
695 Im.Field = readString(Ptr);
696 Im.Kind = readUint8(Ptr);
698 case wasm::WASM_EXTERNAL_FUNCTION:
699 NumImportedFunctions++;
700 Im.SigIndex = readVaruint32(Ptr);
702 case wasm::WASM_EXTERNAL_GLOBAL:
703 NumImportedGlobals++;
704 Im.Global.Type = readUint8(Ptr);
705 Im.Global.Mutable = readVaruint1(Ptr);
707 case wasm::WASM_EXTERNAL_MEMORY:
708 Im.Memory = readLimits(Ptr);
710 case wasm::WASM_EXTERNAL_TABLE:
711 Im.Table = readTable(Ptr);
712 if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC)
713 return make_error<GenericBinaryError>("Invalid table element type",
714 object_error::parse_failed);
717 return make_error<GenericBinaryError>(
718 "Unexpected import kind", object_error::parse_failed);
720 Imports.push_back(Im);
723 return make_error<GenericBinaryError>("Import section ended prematurely",
724 object_error::parse_failed);
725 return Error::success();
728 Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, const uint8_t *End) {
729 uint32_t Count = readVaruint32(Ptr);
730 FunctionTypes.reserve(Count);
731 uint32_t NumTypes = Signatures.size();
733 uint32_t Type = readVaruint32(Ptr);
734 if (Type >= NumTypes)
735 return make_error<GenericBinaryError>("Invalid function type",
736 object_error::parse_failed);
737 FunctionTypes.push_back(Type);
740 return make_error<GenericBinaryError>("Function section ended prematurely",
741 object_error::parse_failed);
742 return Error::success();
745 Error WasmObjectFile::parseTableSection(const uint8_t *Ptr, const uint8_t *End) {
746 uint32_t Count = readVaruint32(Ptr);
747 Tables.reserve(Count);
749 Tables.push_back(readTable(Ptr));
750 if (Tables.back().ElemType != wasm::WASM_TYPE_ANYFUNC) {
751 return make_error<GenericBinaryError>("Invalid table element type",
752 object_error::parse_failed);
756 return make_error<GenericBinaryError>("Table section ended prematurely",
757 object_error::parse_failed);
758 return Error::success();
761 Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, const uint8_t *End) {
762 uint32_t Count = readVaruint32(Ptr);
763 Memories.reserve(Count);
765 Memories.push_back(readLimits(Ptr));
768 return make_error<GenericBinaryError>("Memory section ended prematurely",
769 object_error::parse_failed);
770 return Error::success();
773 Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) {
774 GlobalSection = Sections.size();
775 uint32_t Count = readVaruint32(Ptr);
776 Globals.reserve(Count);
778 wasm::WasmGlobal Global;
779 Global.Index = NumImportedGlobals + Globals.size();
780 Global.Type.Type = readUint8(Ptr);
781 Global.Type.Mutable = readVaruint1(Ptr);
782 if (Error Err = readInitExpr(Global.InitExpr, Ptr))
784 Globals.push_back(Global);
787 return make_error<GenericBinaryError>("Global section ended prematurely",
788 object_error::parse_failed);
789 return Error::success();
792 Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) {
793 uint32_t Count = readVaruint32(Ptr);
794 Exports.reserve(Count);
795 for (uint32_t i = 0; i < Count; i++) {
797 Ex.Name = readString(Ptr);
798 Ex.Kind = readUint8(Ptr);
799 Ex.Index = readVaruint32(Ptr);
801 case wasm::WASM_EXTERNAL_FUNCTION:
802 if (!isValidFunctionIndex(Ex.Index))
803 return make_error<GenericBinaryError>("Invalid function export",
804 object_error::parse_failed);
806 case wasm::WASM_EXTERNAL_GLOBAL:
807 if (!isValidGlobalIndex(Ex.Index))
808 return make_error<GenericBinaryError>("Invalid global export",
809 object_error::parse_failed);
811 case wasm::WASM_EXTERNAL_MEMORY:
812 case wasm::WASM_EXTERNAL_TABLE:
815 return make_error<GenericBinaryError>(
816 "Unexpected export kind", object_error::parse_failed);
818 Exports.push_back(Ex);
821 return make_error<GenericBinaryError>("Export section ended prematurely",
822 object_error::parse_failed);
823 return Error::success();
826 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
827 return Index < NumImportedFunctions + FunctionTypes.size();
830 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
831 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
834 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
835 return Index < NumImportedGlobals + Globals.size();
838 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
839 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
842 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
843 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
846 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
847 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
850 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
851 return Index < Symbols.size() && Symbols[Index].isTypeData();
854 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
855 return Index < Symbols.size() && Symbols[Index].isTypeSection();
858 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
859 assert(isDefinedFunctionIndex(Index));
860 return Functions[Index - NumImportedFunctions];
863 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
864 assert(isDefinedGlobalIndex(Index));
865 return Globals[Index - NumImportedGlobals];
868 Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) {
869 StartFunction = readVaruint32(Ptr);
870 if (!isValidFunctionIndex(StartFunction))
871 return make_error<GenericBinaryError>("Invalid start function",
872 object_error::parse_failed);
873 return Error::success();
876 Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) {
877 CodeSection = Sections.size();
878 const uint8_t *CodeSectionStart = Ptr;
879 uint32_t FunctionCount = readVaruint32(Ptr);
880 if (FunctionCount != FunctionTypes.size()) {
881 return make_error<GenericBinaryError>("Invalid function count",
882 object_error::parse_failed);
885 while (FunctionCount--) {
886 wasm::WasmFunction Function;
887 const uint8_t *FunctionStart = Ptr;
888 uint32_t Size = readVaruint32(Ptr);
889 const uint8_t *FunctionEnd = Ptr + Size;
891 Function.CodeOffset = Ptr - FunctionStart;
892 Function.Index = NumImportedFunctions + Functions.size();
893 Function.CodeSectionOffset = FunctionStart - CodeSectionStart;
894 Function.Size = FunctionEnd - FunctionStart;
896 uint32_t NumLocalDecls = readVaruint32(Ptr);
897 Function.Locals.reserve(NumLocalDecls);
898 while (NumLocalDecls--) {
899 wasm::WasmLocalDecl Decl;
900 Decl.Count = readVaruint32(Ptr);
901 Decl.Type = readUint8(Ptr);
902 Function.Locals.push_back(Decl);
905 uint32_t BodySize = FunctionEnd - Ptr;
906 Function.Body = ArrayRef<uint8_t>(Ptr, BodySize);
907 // This will be set later when reading in the linking metadata section.
908 Function.Comdat = UINT32_MAX;
910 assert(Ptr == FunctionEnd);
911 Functions.push_back(Function);
914 return make_error<GenericBinaryError>("Code section ended prematurely",
915 object_error::parse_failed);
916 return Error::success();
919 Error WasmObjectFile::parseElemSection(const uint8_t *Ptr, const uint8_t *End) {
920 uint32_t Count = readVaruint32(Ptr);
921 ElemSegments.reserve(Count);
923 wasm::WasmElemSegment Segment;
924 Segment.TableIndex = readVaruint32(Ptr);
925 if (Segment.TableIndex != 0) {
926 return make_error<GenericBinaryError>("Invalid TableIndex",
927 object_error::parse_failed);
929 if (Error Err = readInitExpr(Segment.Offset, Ptr))
931 uint32_t NumElems = readVaruint32(Ptr);
933 Segment.Functions.push_back(readVaruint32(Ptr));
935 ElemSegments.push_back(Segment);
938 return make_error<GenericBinaryError>("Elem section ended prematurely",
939 object_error::parse_failed);
940 return Error::success();
943 Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) {
944 DataSection = Sections.size();
945 const uint8_t *Start = Ptr;
946 uint32_t Count = readVaruint32(Ptr);
947 DataSegments.reserve(Count);
950 Segment.Data.MemoryIndex = readVaruint32(Ptr);
951 if (Error Err = readInitExpr(Segment.Data.Offset, Ptr))
953 uint32_t Size = readVaruint32(Ptr);
954 Segment.Data.Content = ArrayRef<uint8_t>(Ptr, Size);
955 // The rest of these Data fields are set later, when reading in the linking
957 Segment.Data.Alignment = 0;
958 Segment.Data.Flags = 0;
959 Segment.Data.Comdat = UINT32_MAX;
960 Segment.SectionOffset = Ptr - Start;
962 DataSegments.push_back(Segment);
965 return make_error<GenericBinaryError>("Data section ended prematurely",
966 object_error::parse_failed);
967 return Error::success();
970 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
971 return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
974 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
978 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; }
980 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
981 uint32_t Result = SymbolRef::SF_None;
982 const WasmSymbol &Sym = getWasmSymbol(Symb);
984 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
985 if (Sym.isBindingWeak())
986 Result |= SymbolRef::SF_Weak;
987 if (!Sym.isBindingLocal())
988 Result |= SymbolRef::SF_Global;
990 Result |= SymbolRef::SF_Hidden;
991 if (!Sym.isDefined())
992 Result |= SymbolRef::SF_Undefined;
993 if (Sym.isTypeFunction())
994 Result |= SymbolRef::SF_Executable;
998 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1001 return BasicSymbolRef(Ref, this);
1004 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1006 Ref.d.a = Symbols.size();
1007 return BasicSymbolRef(Ref, this);
1010 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1011 return Symbols[Symb.d.a];
1014 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1015 return getWasmSymbol(Symb.getRawDataRefImpl());
1018 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1019 return getWasmSymbol(Symb).Info.Name;
1022 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1023 return getSymbolValue(Symb);
1026 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const {
1027 switch (Sym.Info.Kind) {
1028 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1029 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1030 return Sym.Info.ElementIndex;
1031 case wasm::WASM_SYMBOL_TYPE_DATA: {
1032 // The value of a data symbol is the segment offset, plus the symbol
1033 // offset within the segment.
1034 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1035 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1036 assert(Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST);
1037 return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
1039 case wasm::WASM_SYMBOL_TYPE_SECTION:
1042 llvm_unreachable("invalid symbol type");
1045 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1046 return getWasmSymbolValue(getWasmSymbol(Symb));
1049 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1050 llvm_unreachable("not yet implemented");
1054 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1055 llvm_unreachable("not yet implemented");
1059 Expected<SymbolRef::Type>
1060 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1061 const WasmSymbol &Sym = getWasmSymbol(Symb);
1063 switch (Sym.Info.Kind) {
1064 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1065 return SymbolRef::ST_Function;
1066 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1067 return SymbolRef::ST_Other;
1068 case wasm::WASM_SYMBOL_TYPE_DATA:
1069 return SymbolRef::ST_Data;
1070 case wasm::WASM_SYMBOL_TYPE_SECTION:
1071 return SymbolRef::ST_Debug;
1074 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1075 return SymbolRef::ST_Other;
1078 Expected<section_iterator>
1079 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1080 const WasmSymbol& Sym = getWasmSymbol(Symb);
1081 if (Sym.isUndefined())
1082 return section_end();
1085 switch (Sym.Info.Kind) {
1086 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1087 Ref.d.a = CodeSection;
1089 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1090 Ref.d.a = GlobalSection;
1092 case wasm::WASM_SYMBOL_TYPE_DATA:
1093 Ref.d.a = DataSection;
1095 case wasm::WASM_SYMBOL_TYPE_SECTION: {
1096 Ref.d.a = Sym.Info.ElementIndex;
1100 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1102 return section_iterator(SectionRef(Ref, this));
1105 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1107 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
1108 StringRef &Res) const {
1109 const WasmSection &S = Sections[Sec.d.a];
1111 case wasm::WASM_SEC_##X: \
1126 case wasm::WASM_SEC_CUSTOM:
1130 return object_error::invalid_section_index;
1133 return std::error_code();
1136 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1138 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1142 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1143 const WasmSection &S = Sections[Sec.d.a];
1144 return S.Content.size();
1147 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
1148 StringRef &Res) const {
1149 const WasmSection &S = Sections[Sec.d.a];
1150 // This will never fail since wasm sections can never be empty (user-sections
1151 // must have a name and non-user sections each have a defined structure).
1152 Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
1154 return std::error_code();
1157 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1161 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1165 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1166 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1169 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1170 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1173 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1175 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1177 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
1179 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1180 DataRefImpl RelocRef;
1181 RelocRef.d.a = Ref.d.a;
1183 return relocation_iterator(RelocationRef(RelocRef, this));
1186 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1187 const WasmSection &Sec = getWasmSection(Ref);
1188 DataRefImpl RelocRef;
1189 RelocRef.d.a = Ref.d.a;
1190 RelocRef.d.b = Sec.Relocations.size();
1191 return relocation_iterator(RelocationRef(RelocRef, this));
1194 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
1198 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1199 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1203 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1204 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1205 if (Rel.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
1206 return symbol_end();
1208 Sym.d.a = Rel.Index;
1210 return symbol_iterator(SymbolRef(Sym, this));
1213 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1214 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1218 void WasmObjectFile::getRelocationTypeName(
1219 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1220 const wasm::WasmRelocation& Rel = getWasmRelocation(Ref);
1221 StringRef Res = "Unknown";
1223 #define WASM_RELOC(name, value) \
1229 #include "llvm/BinaryFormat/WasmRelocs.def"
1234 Result.append(Res.begin(), Res.end());
1237 section_iterator WasmObjectFile::section_begin() const {
1240 return section_iterator(SectionRef(Ref, this));
1243 section_iterator WasmObjectFile::section_end() const {
1245 Ref.d.a = Sections.size();
1246 return section_iterator(SectionRef(Ref, this));
1249 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1251 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1253 Triple::ArchType WasmObjectFile::getArch() const { return Triple::wasm32; }
1255 SubtargetFeatures WasmObjectFile::getFeatures() const {
1256 return SubtargetFeatures();
1259 bool WasmObjectFile::isRelocatableObject() const {
1260 return HasLinkingSection;
1263 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1264 assert(Ref.d.a < Sections.size());
1265 return Sections[Ref.d.a];
1269 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1270 return getWasmSection(Section.getRawDataRefImpl());
1273 const wasm::WasmRelocation &
1274 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1275 return getWasmRelocation(Ref.getRawDataRefImpl());
1278 const wasm::WasmRelocation &
1279 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1280 assert(Ref.d.a < Sections.size());
1281 const WasmSection& Sec = Sections[Ref.d.a];
1282 assert(Ref.d.b < Sec.Relocations.size());
1283 return Sec.Relocations[Ref.d.b];