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/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"
29 #include <system_error>
31 #define DEBUG_TYPE "wasm-object"
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
);
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
);
59 static int32_t readFloat32(const uint8_t *&Ptr
) {
61 memcpy(&Result
, Ptr
, sizeof(Result
));
62 Ptr
+= sizeof(Result
);
66 static int64_t readFloat64(const uint8_t *&Ptr
) {
68 memcpy(&Result
, Ptr
, sizeof(Result
));
69 Ptr
+= sizeof(Result
);
73 static uint64_t readULEB128(const uint8_t *&Ptr
) {
75 uint64_t Result
= decodeULEB128(Ptr
, &Count
);
80 static StringRef
readString(const uint8_t *&Ptr
) {
81 uint32_t StringLen
= readULEB128(Ptr
);
82 StringRef Return
= StringRef(reinterpret_cast<const char *>(Ptr
), StringLen
);
87 static int64_t readLEB128(const uint8_t *&Ptr
) {
89 uint64_t Result
= decodeSLEB128(Ptr
, &Count
);
94 static uint8_t readVaruint1(const uint8_t *&Ptr
) {
95 int64_t result
= readLEB128(Ptr
);
96 assert(result
<= VARUINT1_MAX
&& result
>= 0);
100 static int8_t readVarint7(const uint8_t *&Ptr
) {
101 int64_t result
= readLEB128(Ptr
);
102 assert(result
<= VARINT7_MAX
&& result
>= VARINT7_MIN
);
106 static uint8_t readVaruint7(const uint8_t *&Ptr
) {
107 uint64_t result
= readULEB128(Ptr
);
108 assert(result
<= VARUINT7_MAX
);
112 static int32_t readVarint32(const uint8_t *&Ptr
) {
113 int64_t result
= readLEB128(Ptr
);
114 assert(result
<= INT32_MAX
&& result
>= INT32_MIN
);
118 static uint32_t readVaruint32(const uint8_t *&Ptr
) {
119 uint64_t result
= readULEB128(Ptr
);
120 assert(result
<= UINT32_MAX
);
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
);
139 case wasm::WASM_OPCODE_I64_CONST
:
140 Expr
.Value
.Int64
= readVarint64(Ptr
);
142 case wasm::WASM_OPCODE_F32_CONST
:
143 Expr
.Value
.Float32
= readFloat32(Ptr
);
145 case wasm::WASM_OPCODE_F64_CONST
:
146 Expr
.Value
.Float64
= readFloat64(Ptr
);
148 case wasm::WASM_OPCODE_GET_GLOBAL
:
149 Expr
.Value
.Global
= readULEB128(Ptr
);
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
);
173 static wasm::WasmTable
readTable(const uint8_t *&Ptr
) {
174 wasm::WasmTable Table
;
175 Table
.ElemType
= readVarint7(Ptr
);
176 Table
.Limits
= readLimits(Ptr
);
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
);
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
);
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
);
208 const uint8_t *Eof
= getPtr(getData().size());
209 const uint8_t *Ptr
= getPtr(4);
212 Err
= make_error
<StringError
>("Missing version number",
213 object_error::parse_failed
);
217 Header
.Version
= readUint32(Ptr
);
218 if (Header
.Version
!= wasm::WasmVersion
) {
219 Err
= make_error
<StringError
>("Bad version number",
220 object_error::parse_failed
);
226 if ((Err
= readSection(Sec
, Ptr
, getPtr(0), Eof
)))
228 if ((Err
= parseSection(Sec
)))
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();
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
);
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
) {
271 uint8_t Type
= readVarint7(Ptr
);
272 uint32_t Size
= readVaruint32(Ptr
);
273 const uint8_t *SubSectionEnd
= Ptr
+ Size
;
275 case wasm::WASM_NAMES_FUNCTION
: {
276 uint32_t Count
= readVaruint32(Ptr
);
278 uint32_t Index
= readVaruint32(Ptr
);
279 StringRef Name
= readString(Ptr
);
281 Symbols
.emplace_back(Name
,
282 WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME
,
283 Sections
.size(), Index
);
287 // Ignore local names for now
288 case wasm::WASM_NAMES_LOCAL
:
293 if (Ptr
!= SubSectionEnd
)
294 return make_error
<GenericBinaryError
>("Name sub-section ended prematurely",
295 object_error::parse_failed
);
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");
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");
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();
360 uint8_t Type
= readVarint7(Ptr
);
361 uint32_t Size
= readVaruint32(Ptr
);
362 const uint8_t *SubSectionEnd
= Ptr
+ Size
;
364 case wasm::WASM_SYMBOL_INFO
: {
365 uint32_t Count
= readVaruint32(Ptr
);
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");
386 case wasm::WASM_DATA_SIZE
:
387 LinkingData
.DataSize
= readVaruint32(Ptr
);
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
);
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
);
420 if (Ptr
!= SubSectionEnd
)
421 return make_error
<GenericBinaryError
>(
422 "Linking sub-section ended prematurely", object_error::parse_failed
);
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
)
438 WasmSection
* WasmObjectFile::findSectionByType(uint32_t Type
) {
439 assert(Type
!= wasm::WASM_SEC_CUSTOM
);
440 for (WasmSection
& Section
: Sections
) {
441 if (Section
.Type
== Type
)
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
);
455 Section
= findSectionByType(SectionCode
);
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
:
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
);
480 return make_error
<GenericBinaryError
>("Bad relocation type: " +
482 object_error::parse_failed
);
484 Section
->Relocations
.push_back(Reloc
);
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
))
498 } else if (Sec
.Name
== "linking") {
499 if (Error Err
= parseLinkingSection(Ptr
, End
))
501 } else if (Sec
.Name
.startswith("reloc.")) {
502 if (Error Err
= parseRelocSection(Sec
.Name
, Ptr
, End
))
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
);
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
);
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
);
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
++) {
547 Im
.Module
= readString(Ptr
);
548 Im
.Field
= readString(Ptr
);
549 Im
.Kind
= readUint8(Ptr
);
551 case wasm::WASM_EXTERNAL_FUNCTION
:
552 NumImportedFunctions
++;
553 Im
.SigIndex
= readVaruint32(Ptr
);
555 case wasm::WASM_EXTERNAL_GLOBAL
:
556 NumImportedGlobals
++;
557 Im
.Global
.Type
= readVarint7(Ptr
);
558 Im
.Global
.Mutable
= readVaruint1(Ptr
);
560 case wasm::WASM_EXTERNAL_MEMORY
:
561 Im
.Memory
= readLimits(Ptr
);
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
);
570 return make_error
<GenericBinaryError
>(
571 "Unexpected import kind", object_error::parse_failed
);
573 Imports
.push_back(Im
);
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
);
585 FunctionTypes
.push_back(readVaruint32(Ptr
));
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
);
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
);
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
);
613 Memories
.push_back(readLimits(Ptr
));
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
);
625 wasm::WasmGlobal Global
;
626 Global
.Type
= readVarint7(Ptr
);
627 Global
.Mutable
= readVaruint1(Ptr
);
628 if (Error Err
= readInitExpr(Global
.InitExpr
, Ptr
))
630 Globals
.push_back(Global
);
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
++) {
644 Ex
.Name
= readString(Ptr
);
645 Ex
.Kind
= readUint8(Ptr
);
646 Ex
.Index
= readVaruint32(Ptr
);
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
);
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
);
659 case wasm::WASM_EXTERNAL_MEMORY
:
660 case wasm::WASM_EXTERNAL_TABLE
:
663 return make_error
<GenericBinaryError
>(
664 "Unexpected export kind", object_error::parse_failed
);
666 Exports
.push_back(Ex
);
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
);
712 assert(Ptr
== FunctionEnd
);
713 Functions
.push_back(Function
);
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
);
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
))
733 uint32_t NumElems
= readVaruint32(Ptr
);
735 Segment
.Functions
.push_back(readVaruint32(Ptr
));
737 ElemSegments
.push_back(Segment
);
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
);
751 Segment
.Data
.MemoryIndex
= readVaruint32(Ptr
);
752 if (Error Err
= readInitExpr(Segment
.Data
.Offset
, Ptr
))
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
;
760 DataSegments
.push_back(Segment
);
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 {
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");
784 Result
|= SymbolRef::SF_Weak
;
786 Result
|= SymbolRef::SF_Global
;
788 Result
|= SymbolRef::SF_Hidden
;
791 case WasmSymbol::SymbolType::FUNCTION_IMPORT
:
792 Result
|= SymbolRef::SF_Undefined
| SymbolRef::SF_Executable
;
794 case WasmSymbol::SymbolType::FUNCTION_EXPORT
:
795 Result
|= SymbolRef::SF_Executable
;
797 case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME
:
798 Result
|= SymbolRef::SF_Executable
;
799 Result
|= SymbolRef::SF_FormatSpecific
;
801 case WasmSymbol::SymbolType::GLOBAL_IMPORT
:
802 Result
|= SymbolRef::SF_Undefined
;
804 case WasmSymbol::SymbolType::GLOBAL_EXPORT
:
811 basic_symbol_iterator
WasmObjectFile::symbol_begin() const {
814 return BasicSymbolRef(Ref
, this);
817 basic_symbol_iterator
WasmObjectFile::symbol_end() const {
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 {
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");
867 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb
) const {
868 llvm_unreachable("not yet implemented");
872 Expected
<SymbolRef::Type
>
873 WasmObjectFile::getSymbolType(DataRefImpl Symb
) const {
874 const WasmSymbol
&Sym
= getWasmSymbol(Symb
);
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 {
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
];
903 case wasm::WASM_SEC_##X: \
918 case wasm::WASM_SEC_CUSTOM
:
922 return object_error::invalid_section_index
;
925 return std::error_code();
928 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec
) const { return 0; }
930 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec
) const {
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()),
946 return std::error_code();
949 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec
) const {
953 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec
) const {
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
;
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 {
990 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref
) const {
991 const wasm::WasmRelocation
&Rel
= getWasmRelocation(Ref
);
995 symbol_iterator
WasmObjectFile::getRelocationSymbol(DataRefImpl Rel
) const {
996 llvm_unreachable("not yet implemented");
998 return symbol_iterator(Ref
);
1001 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref
) const {
1002 const wasm::WasmRelocation
&Rel
= getWasmRelocation(Ref
);
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) \
1017 #include "llvm/BinaryFormat/WasmRelocs/WebAssembly.def"
1022 Result
.append(Res
.begin(), Res
.end());
1025 section_iterator
WasmObjectFile::section_begin() const {
1028 return section_iterator(SectionRef(Ref
, this));
1031 section_iterator
WasmObjectFile::section_end() const {
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
];
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
];