[WebAssembly] Add support for init functions linking metadata
[llvm-core.git] / lib / Object / WasmObjectFile.cpp
blob677fccc6299d8e930e320a65b808eb24dd5cb12c
1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/Triple.h"
14 #include "llvm/BinaryFormat/Wasm.h"
15 #include "llvm/MC/SubtargetFeature.h"
16 #include "llvm/Object/Binary.h"
17 #include "llvm/Object/Error.h"
18 #include "llvm/Object/ObjectFile.h"
19 #include "llvm/Object/SymbolicFile.h"
20 #include "llvm/Object/Wasm.h"
21 #include "llvm/Support/Endian.h"
22 #include "llvm/Support/Error.h"
23 #include "llvm/Support/ErrorHandling.h"
24 #include "llvm/Support/LEB128.h"
25 #include <algorithm>
26 #include <cassert>
27 #include <cstdint>
28 #include <cstring>
29 #include <system_error>
31 #define DEBUG_TYPE "wasm-object"
33 using namespace llvm;
34 using namespace object;
36 Expected<std::unique_ptr<WasmObjectFile>>
37 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
38 Error Err = Error::success();
39 auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
40 if (Err)
41 return std::move(Err);
43 return std::move(ObjectFile);
46 #define VARINT7_MAX ((1<<7)-1)
47 #define VARINT7_MIN (-(1<<7))
48 #define VARUINT7_MAX (1<<7)
49 #define VARUINT1_MAX (1)
51 static uint8_t readUint8(const uint8_t *&Ptr) { return *Ptr++; }
53 static uint32_t readUint32(const uint8_t *&Ptr) {
54 uint32_t Result = support::endian::read32le(Ptr);
55 Ptr += sizeof(Result);
56 return Result;
59 static int32_t readFloat32(const uint8_t *&Ptr) {
60 int32_t Result = 0;
61 memcpy(&Result, Ptr, sizeof(Result));
62 Ptr += sizeof(Result);
63 return Result;
66 static int64_t readFloat64(const uint8_t *&Ptr) {
67 int64_t Result = 0;
68 memcpy(&Result, Ptr, sizeof(Result));
69 Ptr += sizeof(Result);
70 return Result;
73 static uint64_t readULEB128(const uint8_t *&Ptr) {
74 unsigned Count;
75 uint64_t Result = decodeULEB128(Ptr, &Count);
76 Ptr += Count;
77 return Result;
80 static StringRef readString(const uint8_t *&Ptr) {
81 uint32_t StringLen = readULEB128(Ptr);
82 StringRef Return = StringRef(reinterpret_cast<const char *>(Ptr), StringLen);
83 Ptr += StringLen;
84 return Return;
87 static int64_t readLEB128(const uint8_t *&Ptr) {
88 unsigned Count;
89 uint64_t Result = decodeSLEB128(Ptr, &Count);
90 Ptr += Count;
91 return Result;
94 static uint8_t readVaruint1(const uint8_t *&Ptr) {
95 int64_t result = readLEB128(Ptr);
96 assert(result <= VARUINT1_MAX && result >= 0);
97 return result;
100 static int8_t readVarint7(const uint8_t *&Ptr) {
101 int64_t result = readLEB128(Ptr);
102 assert(result <= VARINT7_MAX && result >= VARINT7_MIN);
103 return result;
106 static uint8_t readVaruint7(const uint8_t *&Ptr) {
107 uint64_t result = readULEB128(Ptr);
108 assert(result <= VARUINT7_MAX);
109 return result;
112 static int32_t readVarint32(const uint8_t *&Ptr) {
113 int64_t result = readLEB128(Ptr);
114 assert(result <= INT32_MAX && result >= INT32_MIN);
115 return result;
118 static uint32_t readVaruint32(const uint8_t *&Ptr) {
119 uint64_t result = readULEB128(Ptr);
120 assert(result <= UINT32_MAX);
121 return result;
124 static int64_t readVarint64(const uint8_t *&Ptr) {
125 return readLEB128(Ptr);
128 static uint8_t readOpcode(const uint8_t *&Ptr) {
129 return readUint8(Ptr);
132 static Error readInitExpr(wasm::WasmInitExpr &Expr, const uint8_t *&Ptr) {
133 Expr.Opcode = readOpcode(Ptr);
135 switch (Expr.Opcode) {
136 case wasm::WASM_OPCODE_I32_CONST:
137 Expr.Value.Int32 = readVarint32(Ptr);
138 break;
139 case wasm::WASM_OPCODE_I64_CONST:
140 Expr.Value.Int64 = readVarint64(Ptr);
141 break;
142 case wasm::WASM_OPCODE_F32_CONST:
143 Expr.Value.Float32 = readFloat32(Ptr);
144 break;
145 case wasm::WASM_OPCODE_F64_CONST:
146 Expr.Value.Float64 = readFloat64(Ptr);
147 break;
148 case wasm::WASM_OPCODE_GET_GLOBAL:
149 Expr.Value.Global = readULEB128(Ptr);
150 break;
151 default:
152 return make_error<GenericBinaryError>("Invalid opcode in init_expr",
153 object_error::parse_failed);
156 uint8_t EndOpcode = readOpcode(Ptr);
157 if (EndOpcode != wasm::WASM_OPCODE_END) {
158 return make_error<GenericBinaryError>("Invalid init_expr",
159 object_error::parse_failed);
161 return Error::success();
164 static wasm::WasmLimits readLimits(const uint8_t *&Ptr) {
165 wasm::WasmLimits Result;
166 Result.Flags = readVaruint1(Ptr);
167 Result.Initial = readVaruint32(Ptr);
168 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
169 Result.Maximum = readVaruint32(Ptr);
170 return Result;
173 static wasm::WasmTable readTable(const uint8_t *&Ptr) {
174 wasm::WasmTable Table;
175 Table.ElemType = readVarint7(Ptr);
176 Table.Limits = readLimits(Ptr);
177 return Table;
180 static Error readSection(WasmSection &Section, const uint8_t *&Ptr,
181 const uint8_t *Start, const uint8_t *Eof) {
182 Section.Offset = Ptr - Start;
183 Section.Type = readVaruint7(Ptr);
184 uint32_t Size = readVaruint32(Ptr);
185 if (Size == 0)
186 return make_error<StringError>("Zero length section",
187 object_error::parse_failed);
188 if (Ptr + Size > Eof)
189 return make_error<StringError>("Section too large",
190 object_error::parse_failed);
191 Section.Content = ArrayRef<uint8_t>(Ptr, Size);
192 Ptr += Size;
193 return Error::success();
196 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
197 : ObjectFile(Binary::ID_Wasm, Buffer) {
198 LinkingData.DataSize = 0;
200 ErrorAsOutParameter ErrAsOutParam(&Err);
201 Header.Magic = getData().substr(0, 4);
202 if (Header.Magic != StringRef("\0asm", 4)) {
203 Err = make_error<StringError>("Bad magic number",
204 object_error::parse_failed);
205 return;
208 const uint8_t *Eof = getPtr(getData().size());
209 const uint8_t *Ptr = getPtr(4);
211 if (Ptr + 4 > Eof) {
212 Err = make_error<StringError>("Missing version number",
213 object_error::parse_failed);
214 return;
217 Header.Version = readUint32(Ptr);
218 if (Header.Version != wasm::WasmVersion) {
219 Err = make_error<StringError>("Bad version number",
220 object_error::parse_failed);
221 return;
224 WasmSection Sec;
225 while (Ptr < Eof) {
226 if ((Err = readSection(Sec, Ptr, getPtr(0), Eof)))
227 return;
228 if ((Err = parseSection(Sec)))
229 return;
231 Sections.push_back(Sec);
235 Error WasmObjectFile::parseSection(WasmSection &Sec) {
236 const uint8_t* Start = Sec.Content.data();
237 const uint8_t* End = Start + Sec.Content.size();
238 switch (Sec.Type) {
239 case wasm::WASM_SEC_CUSTOM:
240 return parseCustomSection(Sec, Start, End);
241 case wasm::WASM_SEC_TYPE:
242 return parseTypeSection(Start, End);
243 case wasm::WASM_SEC_IMPORT:
244 return parseImportSection(Start, End);
245 case wasm::WASM_SEC_FUNCTION:
246 return parseFunctionSection(Start, End);
247 case wasm::WASM_SEC_TABLE:
248 return parseTableSection(Start, End);
249 case wasm::WASM_SEC_MEMORY:
250 return parseMemorySection(Start, End);
251 case wasm::WASM_SEC_GLOBAL:
252 return parseGlobalSection(Start, End);
253 case wasm::WASM_SEC_EXPORT:
254 return parseExportSection(Start, End);
255 case wasm::WASM_SEC_START:
256 return parseStartSection(Start, End);
257 case wasm::WASM_SEC_ELEM:
258 return parseElemSection(Start, End);
259 case wasm::WASM_SEC_CODE:
260 return parseCodeSection(Start, End);
261 case wasm::WASM_SEC_DATA:
262 return parseDataSection(Start, End);
263 default:
264 return make_error<GenericBinaryError>("Bad section type",
265 object_error::parse_failed);
269 Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) {
270 while (Ptr < End) {
271 uint8_t Type = readVarint7(Ptr);
272 uint32_t Size = readVaruint32(Ptr);
273 const uint8_t *SubSectionEnd = Ptr + Size;
274 switch (Type) {
275 case wasm::WASM_NAMES_FUNCTION: {
276 uint32_t Count = readVaruint32(Ptr);
277 while (Count--) {
278 uint32_t Index = readVaruint32(Ptr);
279 StringRef Name = readString(Ptr);
280 if (!Name.empty())
281 Symbols.emplace_back(Name,
282 WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME,
283 Sections.size(), Index);
285 break;
287 // Ignore local names for now
288 case wasm::WASM_NAMES_LOCAL:
289 default:
290 Ptr += Size;
291 break;
293 if (Ptr != SubSectionEnd)
294 return make_error<GenericBinaryError>("Name sub-section ended prematurely",
295 object_error::parse_failed);
298 if (Ptr != End)
299 return make_error<GenericBinaryError>("Name section ended prematurely",
300 object_error::parse_failed);
301 return Error::success();
304 void WasmObjectFile::populateSymbolTable() {
305 // Add imports to symbol table
306 size_t ImportIndex = 0;
307 size_t GlobalIndex = 0;
308 size_t FunctionIndex = 0;
309 for (const wasm::WasmImport& Import : Imports) {
310 switch (Import.Kind) {
311 case wasm::WASM_EXTERNAL_GLOBAL:
312 assert(Import.Global.Type == wasm::WASM_TYPE_I32);
313 SymbolMap.try_emplace(Import.Field, Symbols.size());
314 Symbols.emplace_back(Import.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT,
315 ImportSection, GlobalIndex++, ImportIndex);
316 DEBUG(dbgs() << "Adding import: " << Symbols.back()
317 << " sym index:" << Symbols.size() << "\n");
318 break;
319 case wasm::WASM_EXTERNAL_FUNCTION:
320 SymbolMap.try_emplace(Import.Field, Symbols.size());
321 Symbols.emplace_back(Import.Field,
322 WasmSymbol::SymbolType::FUNCTION_IMPORT,
323 ImportSection, FunctionIndex++, ImportIndex);
324 DEBUG(dbgs() << "Adding import: " << Symbols.back()
325 << " sym index:" << Symbols.size() << "\n");
326 break;
327 default:
328 break;
330 ImportIndex++;
333 // Add exports to symbol table
334 for (const wasm::WasmExport& Export : Exports) {
335 if (Export.Kind == wasm::WASM_EXTERNAL_FUNCTION ||
336 Export.Kind == wasm::WASM_EXTERNAL_GLOBAL) {
337 WasmSymbol::SymbolType ExportType =
338 Export.Kind == wasm::WASM_EXTERNAL_FUNCTION
339 ? WasmSymbol::SymbolType::FUNCTION_EXPORT
340 : WasmSymbol::SymbolType::GLOBAL_EXPORT;
341 SymbolMap.try_emplace(Export.Name, Symbols.size());
342 Symbols.emplace_back(Export.Name, ExportType,
343 ExportSection, Export.Index);
344 DEBUG(dbgs() << "Adding export: " << Symbols.back()
345 << " sym index:" << Symbols.size() << "\n");
350 Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr,
351 const uint8_t *End) {
352 HasLinkingSection = true;
354 // Only populate the symbol table with imports and exports if the object
355 // has a linking section (i.e. its a relocatable object file). Otherwise
356 // the global might not represent symbols at all.
357 populateSymbolTable();
359 while (Ptr < End) {
360 uint8_t Type = readVarint7(Ptr);
361 uint32_t Size = readVaruint32(Ptr);
362 const uint8_t *SubSectionEnd = Ptr + Size;
363 switch (Type) {
364 case wasm::WASM_SYMBOL_INFO: {
365 uint32_t Count = readVaruint32(Ptr);
366 while (Count--) {
367 StringRef Symbol = readString(Ptr);
368 DEBUG(dbgs() << "reading syminfo: " << Symbol << "\n");
369 uint32_t Flags = readVaruint32(Ptr);
370 auto iter = SymbolMap.find(Symbol);
371 if (iter == SymbolMap.end()) {
372 return make_error<GenericBinaryError>(
373 "Invalid symbol name in linking section: " + Symbol,
374 object_error::parse_failed);
376 uint32_t SymIndex = iter->second;
377 assert(SymIndex < Symbols.size());
378 Symbols[SymIndex].Flags = Flags;
379 DEBUG(dbgs() << "Set symbol flags index:"
380 << SymIndex << " name:"
381 << Symbols[SymIndex].Name << " expected:"
382 << Symbol << " flags: " << Flags << "\n");
384 break;
386 case wasm::WASM_DATA_SIZE:
387 LinkingData.DataSize = readVaruint32(Ptr);
388 break;
389 case wasm::WASM_SEGMENT_INFO: {
390 uint32_t Count = readVaruint32(Ptr);
391 if (Count > DataSegments.size())
392 return make_error<GenericBinaryError>("Too many segment names",
393 object_error::parse_failed);
394 for (uint32_t i = 0; i < Count; i++) {
395 DataSegments[i].Data.Name = readString(Ptr);
396 DataSegments[i].Data.Alignment = readVaruint32(Ptr);
397 DataSegments[i].Data.Flags = readVaruint32(Ptr);
399 break;
401 case wasm::WASM_INIT_FUNCS: {
402 uint32_t Count = readVaruint32(Ptr);
403 LinkingData.InitFunctions.reserve(Count);
404 for (uint32_t i = 0; i < Count; i++) {
405 wasm::WasmInitFunc Init;
406 Init.Priority = readVaruint32(Ptr);
407 Init.FunctionIndex = readVaruint32(Ptr);
408 if (!isValidFunctionIndex(Init.FunctionIndex))
409 return make_error<GenericBinaryError>("Invalid function index: " +
410 Twine(Init.FunctionIndex),
411 object_error::parse_failed);
412 LinkingData.InitFunctions.emplace_back(Init);
414 break;
416 default:
417 Ptr += Size;
418 break;
420 if (Ptr != SubSectionEnd)
421 return make_error<GenericBinaryError>(
422 "Linking sub-section ended prematurely", object_error::parse_failed);
424 if (Ptr != End)
425 return make_error<GenericBinaryError>("Linking section ended prematurely",
426 object_error::parse_failed);
427 return Error::success();
430 WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) {
431 for (WasmSection& Section : Sections) {
432 if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name)
433 return &Section;
435 return nullptr;
438 WasmSection* WasmObjectFile::findSectionByType(uint32_t Type) {
439 assert(Type != wasm::WASM_SEC_CUSTOM);
440 for (WasmSection& Section : Sections) {
441 if (Section.Type == Type)
442 return &Section;
444 return nullptr;
447 Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr,
448 const uint8_t *End) {
449 uint8_t SectionCode = readVarint7(Ptr);
450 WasmSection* Section = nullptr;
451 if (SectionCode == wasm::WASM_SEC_CUSTOM) {
452 StringRef Name = readString(Ptr);
453 Section = findCustomSectionByName(Name);
454 } else {
455 Section = findSectionByType(SectionCode);
457 if (!Section)
458 return make_error<GenericBinaryError>("Invalid section code",
459 object_error::parse_failed);
460 uint32_t RelocCount = readVaruint32(Ptr);
461 while (RelocCount--) {
462 wasm::WasmRelocation Reloc;
463 memset(&Reloc, 0, sizeof(Reloc));
464 Reloc.Type = readVaruint32(Ptr);
465 Reloc.Offset = readVaruint32(Ptr);
466 Reloc.Index = readVaruint32(Ptr);
467 switch (Reloc.Type) {
468 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
469 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
470 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
471 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
472 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
473 break;
474 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
475 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
476 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
477 Reloc.Addend = readVarint32(Ptr);
478 break;
479 default:
480 return make_error<GenericBinaryError>("Bad relocation type: " +
481 Twine(Reloc.Type),
482 object_error::parse_failed);
484 Section->Relocations.push_back(Reloc);
486 if (Ptr != End)
487 return make_error<GenericBinaryError>("Reloc section ended prematurely",
488 object_error::parse_failed);
489 return Error::success();
492 Error WasmObjectFile::parseCustomSection(WasmSection &Sec,
493 const uint8_t *Ptr, const uint8_t *End) {
494 Sec.Name = readString(Ptr);
495 if (Sec.Name == "name") {
496 if (Error Err = parseNameSection(Ptr, End))
497 return Err;
498 } else if (Sec.Name == "linking") {
499 if (Error Err = parseLinkingSection(Ptr, End))
500 return Err;
501 } else if (Sec.Name.startswith("reloc.")) {
502 if (Error Err = parseRelocSection(Sec.Name, Ptr, End))
503 return Err;
505 return Error::success();
508 Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) {
509 uint32_t Count = readVaruint32(Ptr);
510 Signatures.reserve(Count);
511 while (Count--) {
512 wasm::WasmSignature Sig;
513 Sig.ReturnType = wasm::WASM_TYPE_NORESULT;
514 int8_t Form = readVarint7(Ptr);
515 if (Form != wasm::WASM_TYPE_FUNC) {
516 return make_error<GenericBinaryError>("Invalid signature type",
517 object_error::parse_failed);
519 uint32_t ParamCount = readVaruint32(Ptr);
520 Sig.ParamTypes.reserve(ParamCount);
521 while (ParamCount--) {
522 uint32_t ParamType = readVarint7(Ptr);
523 Sig.ParamTypes.push_back(ParamType);
525 uint32_t ReturnCount = readVaruint32(Ptr);
526 if (ReturnCount) {
527 if (ReturnCount != 1) {
528 return make_error<GenericBinaryError>(
529 "Multiple return types not supported", object_error::parse_failed);
531 Sig.ReturnType = readVarint7(Ptr);
533 Signatures.push_back(Sig);
535 if (Ptr != End)
536 return make_error<GenericBinaryError>("Type section ended prematurely",
537 object_error::parse_failed);
538 return Error::success();
541 Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) {
542 ImportSection = Sections.size();
543 uint32_t Count = readVaruint32(Ptr);
544 Imports.reserve(Count);
545 for (uint32_t i = 0; i < Count; i++) {
546 wasm::WasmImport Im;
547 Im.Module = readString(Ptr);
548 Im.Field = readString(Ptr);
549 Im.Kind = readUint8(Ptr);
550 switch (Im.Kind) {
551 case wasm::WASM_EXTERNAL_FUNCTION:
552 NumImportedFunctions++;
553 Im.SigIndex = readVaruint32(Ptr);
554 break;
555 case wasm::WASM_EXTERNAL_GLOBAL:
556 NumImportedGlobals++;
557 Im.Global.Type = readVarint7(Ptr);
558 Im.Global.Mutable = readVaruint1(Ptr);
559 break;
560 case wasm::WASM_EXTERNAL_MEMORY:
561 Im.Memory = readLimits(Ptr);
562 break;
563 case wasm::WASM_EXTERNAL_TABLE:
564 Im.Table = readTable(Ptr);
565 if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC)
566 return make_error<GenericBinaryError>("Invalid table element type",
567 object_error::parse_failed);
568 break;
569 default:
570 return make_error<GenericBinaryError>(
571 "Unexpected import kind", object_error::parse_failed);
573 Imports.push_back(Im);
575 if (Ptr != End)
576 return make_error<GenericBinaryError>("Import section ended prematurely",
577 object_error::parse_failed);
578 return Error::success();
581 Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, const uint8_t *End) {
582 uint32_t Count = readVaruint32(Ptr);
583 FunctionTypes.reserve(Count);
584 while (Count--) {
585 FunctionTypes.push_back(readVaruint32(Ptr));
587 if (Ptr != End)
588 return make_error<GenericBinaryError>("Function section ended prematurely",
589 object_error::parse_failed);
590 return Error::success();
593 Error WasmObjectFile::parseTableSection(const uint8_t *Ptr, const uint8_t *End) {
594 uint32_t Count = readVaruint32(Ptr);
595 Tables.reserve(Count);
596 while (Count--) {
597 Tables.push_back(readTable(Ptr));
598 if (Tables.back().ElemType != wasm::WASM_TYPE_ANYFUNC) {
599 return make_error<GenericBinaryError>("Invalid table element type",
600 object_error::parse_failed);
603 if (Ptr != End)
604 return make_error<GenericBinaryError>("Table section ended prematurely",
605 object_error::parse_failed);
606 return Error::success();
609 Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, const uint8_t *End) {
610 uint32_t Count = readVaruint32(Ptr);
611 Memories.reserve(Count);
612 while (Count--) {
613 Memories.push_back(readLimits(Ptr));
615 if (Ptr != End)
616 return make_error<GenericBinaryError>("Memory section ended prematurely",
617 object_error::parse_failed);
618 return Error::success();
621 Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) {
622 uint32_t Count = readVaruint32(Ptr);
623 Globals.reserve(Count);
624 while (Count--) {
625 wasm::WasmGlobal Global;
626 Global.Type = readVarint7(Ptr);
627 Global.Mutable = readVaruint1(Ptr);
628 if (Error Err = readInitExpr(Global.InitExpr, Ptr))
629 return Err;
630 Globals.push_back(Global);
632 if (Ptr != End)
633 return make_error<GenericBinaryError>("Global section ended prematurely",
634 object_error::parse_failed);
635 return Error::success();
638 Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) {
639 ExportSection = Sections.size();
640 uint32_t Count = readVaruint32(Ptr);
641 Exports.reserve(Count);
642 for (uint32_t i = 0; i < Count; i++) {
643 wasm::WasmExport Ex;
644 Ex.Name = readString(Ptr);
645 Ex.Kind = readUint8(Ptr);
646 Ex.Index = readVaruint32(Ptr);
647 switch (Ex.Kind) {
648 case wasm::WASM_EXTERNAL_FUNCTION:
649 if (Ex.Index >= FunctionTypes.size() + NumImportedFunctions)
650 return make_error<GenericBinaryError>("Invalid function export",
651 object_error::parse_failed);
652 break;
653 case wasm::WASM_EXTERNAL_GLOBAL: {
654 if (Ex.Index >= Globals.size() + NumImportedGlobals)
655 return make_error<GenericBinaryError>("Invalid global export",
656 object_error::parse_failed);
657 break;
659 case wasm::WASM_EXTERNAL_MEMORY:
660 case wasm::WASM_EXTERNAL_TABLE:
661 break;
662 default:
663 return make_error<GenericBinaryError>(
664 "Unexpected export kind", object_error::parse_failed);
666 Exports.push_back(Ex);
668 if (Ptr != End)
669 return make_error<GenericBinaryError>("Export section ended prematurely",
670 object_error::parse_failed);
671 return Error::success();
674 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
675 return Index < FunctionTypes.size() + NumImportedFunctions;
678 Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) {
679 StartFunction = readVaruint32(Ptr);
680 if (!isValidFunctionIndex(StartFunction))
681 return make_error<GenericBinaryError>("Invalid start function",
682 object_error::parse_failed);
683 return Error::success();
686 Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) {
687 uint32_t FunctionCount = readVaruint32(Ptr);
688 if (FunctionCount != FunctionTypes.size()) {
689 return make_error<GenericBinaryError>("Invalid function count",
690 object_error::parse_failed);
693 CodeSection = ArrayRef<uint8_t>(Ptr, End - Ptr);
695 while (FunctionCount--) {
696 wasm::WasmFunction Function;
697 uint32_t FunctionSize = readVaruint32(Ptr);
698 const uint8_t *FunctionEnd = Ptr + FunctionSize;
700 uint32_t NumLocalDecls = readVaruint32(Ptr);
701 Function.Locals.reserve(NumLocalDecls);
702 while (NumLocalDecls--) {
703 wasm::WasmLocalDecl Decl;
704 Decl.Count = readVaruint32(Ptr);
705 Decl.Type = readVarint7(Ptr);
706 Function.Locals.push_back(Decl);
709 uint32_t BodySize = FunctionEnd - Ptr;
710 Function.Body = ArrayRef<uint8_t>(Ptr, BodySize);
711 Ptr += BodySize;
712 assert(Ptr == FunctionEnd);
713 Functions.push_back(Function);
715 if (Ptr != End)
716 return make_error<GenericBinaryError>("Code section ended prematurely",
717 object_error::parse_failed);
718 return Error::success();
721 Error WasmObjectFile::parseElemSection(const uint8_t *Ptr, const uint8_t *End) {
722 uint32_t Count = readVaruint32(Ptr);
723 ElemSegments.reserve(Count);
724 while (Count--) {
725 wasm::WasmElemSegment Segment;
726 Segment.TableIndex = readVaruint32(Ptr);
727 if (Segment.TableIndex != 0) {
728 return make_error<GenericBinaryError>("Invalid TableIndex",
729 object_error::parse_failed);
731 if (Error Err = readInitExpr(Segment.Offset, Ptr))
732 return Err;
733 uint32_t NumElems = readVaruint32(Ptr);
734 while (NumElems--) {
735 Segment.Functions.push_back(readVaruint32(Ptr));
737 ElemSegments.push_back(Segment);
739 if (Ptr != End)
740 return make_error<GenericBinaryError>("Elem section ended prematurely",
741 object_error::parse_failed);
742 return Error::success();
745 Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) {
746 const uint8_t *Start = Ptr;
747 uint32_t Count = readVaruint32(Ptr);
748 DataSegments.reserve(Count);
749 while (Count--) {
750 WasmSegment Segment;
751 Segment.Data.MemoryIndex = readVaruint32(Ptr);
752 if (Error Err = readInitExpr(Segment.Data.Offset, Ptr))
753 return Err;
754 uint32_t Size = readVaruint32(Ptr);
755 Segment.Data.Content = ArrayRef<uint8_t>(Ptr, Size);
756 Segment.Data.Alignment = 0;
757 Segment.Data.Flags = 0;
758 Segment.SectionOffset = Ptr - Start;
759 Ptr += Size;
760 DataSegments.push_back(Segment);
762 if (Ptr != End)
763 return make_error<GenericBinaryError>("Data section ended prematurely",
764 object_error::parse_failed);
765 return Error::success();
768 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
769 return reinterpret_cast<const uint8_t *>(getData().substr(Offset, 1).data());
772 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
773 return Header;
776 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; }
778 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
779 uint32_t Result = SymbolRef::SF_None;
780 const WasmSymbol &Sym = getWasmSymbol(Symb);
782 DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
783 if (Sym.isWeak())
784 Result |= SymbolRef::SF_Weak;
785 if (!Sym.isLocal())
786 Result |= SymbolRef::SF_Global;
787 if (Sym.isHidden())
788 Result |= SymbolRef::SF_Hidden;
790 switch (Sym.Type) {
791 case WasmSymbol::SymbolType::FUNCTION_IMPORT:
792 Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable;
793 break;
794 case WasmSymbol::SymbolType::FUNCTION_EXPORT:
795 Result |= SymbolRef::SF_Executable;
796 break;
797 case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
798 Result |= SymbolRef::SF_Executable;
799 Result |= SymbolRef::SF_FormatSpecific;
800 break;
801 case WasmSymbol::SymbolType::GLOBAL_IMPORT:
802 Result |= SymbolRef::SF_Undefined;
803 break;
804 case WasmSymbol::SymbolType::GLOBAL_EXPORT:
805 break;
808 return Result;
811 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
812 DataRefImpl Ref;
813 Ref.d.a = 0;
814 return BasicSymbolRef(Ref, this);
817 basic_symbol_iterator WasmObjectFile::symbol_end() const {
818 DataRefImpl Ref;
819 Ref.d.a = Symbols.size();
820 return BasicSymbolRef(Ref, this);
823 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
824 return Symbols[Symb.d.a];
827 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
828 return getWasmSymbol(Symb.getRawDataRefImpl());
831 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
832 return getWasmSymbol(Symb).Name;
835 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
836 return getSymbolValue(Symb);
839 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const {
840 switch (Sym.Type) {
841 case WasmSymbol::SymbolType::FUNCTION_IMPORT:
842 case WasmSymbol::SymbolType::GLOBAL_IMPORT:
843 case WasmSymbol::SymbolType::FUNCTION_EXPORT:
844 case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
845 return Sym.ElementIndex;
846 case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
847 uint32_t GlobalIndex = Sym.ElementIndex - NumImportedGlobals;
848 assert(GlobalIndex < Globals.size());
849 const wasm::WasmGlobal& Global = Globals[GlobalIndex];
850 // WasmSymbols correspond only to I32_CONST globals
851 assert(Global.InitExpr.Opcode == wasm::WASM_OPCODE_I32_CONST);
852 return Global.InitExpr.Value.Int32;
855 llvm_unreachable("invalid symbol type");
858 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
859 return getWasmSymbolValue(getWasmSymbol(Symb));
862 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
863 llvm_unreachable("not yet implemented");
864 return 0;
867 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
868 llvm_unreachable("not yet implemented");
869 return 0;
872 Expected<SymbolRef::Type>
873 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
874 const WasmSymbol &Sym = getWasmSymbol(Symb);
876 switch (Sym.Type) {
877 case WasmSymbol::SymbolType::FUNCTION_IMPORT:
878 case WasmSymbol::SymbolType::FUNCTION_EXPORT:
879 case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
880 return SymbolRef::ST_Function;
881 case WasmSymbol::SymbolType::GLOBAL_IMPORT:
882 case WasmSymbol::SymbolType::GLOBAL_EXPORT:
883 return SymbolRef::ST_Data;
886 llvm_unreachable("Unknown WasmSymbol::SymbolType");
887 return SymbolRef::ST_Other;
890 Expected<section_iterator>
891 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
892 DataRefImpl Ref;
893 Ref.d.a = getWasmSymbol(Symb).Section;
894 return section_iterator(SectionRef(Ref, this));
897 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
899 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
900 StringRef &Res) const {
901 const WasmSection &S = Sections[Sec.d.a];
902 #define ECase(X) \
903 case wasm::WASM_SEC_##X: \
904 Res = #X; \
905 break
906 switch (S.Type) {
907 ECase(TYPE);
908 ECase(IMPORT);
909 ECase(FUNCTION);
910 ECase(TABLE);
911 ECase(MEMORY);
912 ECase(GLOBAL);
913 ECase(EXPORT);
914 ECase(START);
915 ECase(ELEM);
916 ECase(CODE);
917 ECase(DATA);
918 case wasm::WASM_SEC_CUSTOM:
919 Res = S.Name;
920 break;
921 default:
922 return object_error::invalid_section_index;
924 #undef ECase
925 return std::error_code();
928 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
930 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
931 return Sec.d.a;
934 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
935 const WasmSection &S = Sections[Sec.d.a];
936 return S.Content.size();
939 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
940 StringRef &Res) const {
941 const WasmSection &S = Sections[Sec.d.a];
942 // This will never fail since wasm sections can never be empty (user-sections
943 // must have a name and non-user sections each have a defined structure).
944 Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
945 S.Content.size());
946 return std::error_code();
949 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
950 return 1;
953 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
954 return false;
957 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
958 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
961 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
962 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
965 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
967 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
969 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
971 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
972 DataRefImpl RelocRef;
973 RelocRef.d.a = Ref.d.a;
974 RelocRef.d.b = 0;
975 return relocation_iterator(RelocationRef(RelocRef, this));
978 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
979 const WasmSection &Sec = getWasmSection(Ref);
980 DataRefImpl RelocRef;
981 RelocRef.d.a = Ref.d.a;
982 RelocRef.d.b = Sec.Relocations.size();
983 return relocation_iterator(RelocationRef(RelocRef, this));
986 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
987 Rel.d.b++;
990 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
991 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
992 return Rel.Offset;
995 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
996 llvm_unreachable("not yet implemented");
997 SymbolRef Ref;
998 return symbol_iterator(Ref);
1001 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1002 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1003 return Rel.Type;
1006 void WasmObjectFile::getRelocationTypeName(
1007 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1008 const wasm::WasmRelocation& Rel = getWasmRelocation(Ref);
1009 StringRef Res = "Unknown";
1011 #define WASM_RELOC(name, value) \
1012 case wasm::name: \
1013 Res = #name; \
1014 break;
1016 switch (Rel.Type) {
1017 #include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
1020 #undef WASM_RELOC
1022 Result.append(Res.begin(), Res.end());
1025 section_iterator WasmObjectFile::section_begin() const {
1026 DataRefImpl Ref;
1027 Ref.d.a = 0;
1028 return section_iterator(SectionRef(Ref, this));
1031 section_iterator WasmObjectFile::section_end() const {
1032 DataRefImpl Ref;
1033 Ref.d.a = Sections.size();
1034 return section_iterator(SectionRef(Ref, this));
1037 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1039 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1041 unsigned WasmObjectFile::getArch() const { return Triple::wasm32; }
1043 SubtargetFeatures WasmObjectFile::getFeatures() const {
1044 return SubtargetFeatures();
1047 bool WasmObjectFile::isRelocatableObject() const {
1048 return HasLinkingSection;
1051 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1052 assert(Ref.d.a < Sections.size());
1053 return Sections[Ref.d.a];
1056 const WasmSection &
1057 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1058 return getWasmSection(Section.getRawDataRefImpl());
1061 const wasm::WasmRelocation &
1062 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1063 return getWasmRelocation(Ref.getRawDataRefImpl());
1066 const wasm::WasmRelocation &
1067 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1068 assert(Ref.d.a < Sections.size());
1069 const WasmSection& Sec = Sections[Ref.d.a];
1070 assert(Ref.d.b < Sec.Relocations.size());
1071 return Sec.Relocations[Ref.d.b];