1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ADT/ArrayRef.h"
10 #include "llvm/ADT/DenseSet.h"
11 #include "llvm/ADT/SmallSet.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/ADT/StringSet.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/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"
27 #include "llvm/Support/ScopedPrinter.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <cstdint>
31 #include <cstring>
32
33 #define DEBUG_TYPE "wasm-object"
34
35 using namespace llvm;
36 using namespace object;
37
print(raw_ostream & Out) const38 void WasmSymbol::print(raw_ostream &Out) const {
39 Out << "Name=" << Info.Name
40 << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
41 << Twine::utohexstr(Info.Flags);
42 if (!isTypeData()) {
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;
48 }
49 }
50
51 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const52 LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
53 #endif
54
55 Expected<std::unique_ptr<WasmObjectFile>>
createWasmObjectFile(MemoryBufferRef Buffer)56 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
57 Error Err = Error::success();
58 auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
59 if (Err)
60 return std::move(Err);
61
62 return std::move(ObjectFile);
63 }
64
65 #define VARINT7_MAX ((1 << 7) - 1)
66 #define VARINT7_MIN (-(1 << 7))
67 #define VARUINT7_MAX (1 << 7)
68 #define VARUINT1_MAX (1)
69
readUint8(WasmObjectFile::ReadContext & Ctx)70 static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
71 if (Ctx.Ptr == Ctx.End)
72 report_fatal_error("EOF while reading uint8");
73 return *Ctx.Ptr++;
74 }
75
readUint32(WasmObjectFile::ReadContext & Ctx)76 static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
77 if (Ctx.Ptr + 4 > Ctx.End)
78 report_fatal_error("EOF while reading uint32");
79 uint32_t Result = support::endian::read32le(Ctx.Ptr);
80 Ctx.Ptr += 4;
81 return Result;
82 }
83
readFloat32(WasmObjectFile::ReadContext & Ctx)84 static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
85 if (Ctx.Ptr + 4 > Ctx.End)
86 report_fatal_error("EOF while reading float64");
87 int32_t Result = 0;
88 memcpy(&Result, Ctx.Ptr, sizeof(Result));
89 Ctx.Ptr += sizeof(Result);
90 return Result;
91 }
92
readFloat64(WasmObjectFile::ReadContext & Ctx)93 static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
94 if (Ctx.Ptr + 8 > Ctx.End)
95 report_fatal_error("EOF while reading float64");
96 int64_t Result = 0;
97 memcpy(&Result, Ctx.Ptr, sizeof(Result));
98 Ctx.Ptr += sizeof(Result);
99 return Result;
100 }
101
readULEB128(WasmObjectFile::ReadContext & Ctx)102 static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
103 unsigned Count;
104 const char *Error = nullptr;
105 uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
106 if (Error)
107 report_fatal_error(Error);
108 Ctx.Ptr += Count;
109 return Result;
110 }
111
readString(WasmObjectFile::ReadContext & Ctx)112 static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
113 uint32_t StringLen = readULEB128(Ctx);
114 if (Ctx.Ptr + StringLen > Ctx.End)
115 report_fatal_error("EOF while reading string");
116 StringRef Return =
117 StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
118 Ctx.Ptr += StringLen;
119 return Return;
120 }
121
readLEB128(WasmObjectFile::ReadContext & Ctx)122 static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
123 unsigned Count;
124 const char *Error = nullptr;
125 uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
126 if (Error)
127 report_fatal_error(Error);
128 Ctx.Ptr += Count;
129 return Result;
130 }
131
readVaruint1(WasmObjectFile::ReadContext & Ctx)132 static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
133 int64_t Result = readLEB128(Ctx);
134 if (Result > VARUINT1_MAX || Result < 0)
135 report_fatal_error("LEB is outside Varuint1 range");
136 return Result;
137 }
138
readVarint32(WasmObjectFile::ReadContext & Ctx)139 static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
140 int64_t Result = readLEB128(Ctx);
141 if (Result > INT32_MAX || Result < INT32_MIN)
142 report_fatal_error("LEB is outside Varint32 range");
143 return Result;
144 }
145
readVaruint32(WasmObjectFile::ReadContext & Ctx)146 static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
147 uint64_t Result = readULEB128(Ctx);
148 if (Result > UINT32_MAX)
149 report_fatal_error("LEB is outside Varuint32 range");
150 return Result;
151 }
152
readVarint64(WasmObjectFile::ReadContext & Ctx)153 static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
154 return readLEB128(Ctx);
155 }
156
readVaruint64(WasmObjectFile::ReadContext & Ctx)157 static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
158 return readULEB128(Ctx);
159 }
160
readOpcode(WasmObjectFile::ReadContext & Ctx)161 static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
162 return readUint8(Ctx);
163 }
164
readInitExpr(wasm::WasmInitExpr & Expr,WasmObjectFile::ReadContext & Ctx)165 static Error readInitExpr(wasm::WasmInitExpr &Expr,
166 WasmObjectFile::ReadContext &Ctx) {
167 auto Start = Ctx.Ptr;
168
169 Expr.Extended = false;
170 Expr.Inst.Opcode = readOpcode(Ctx);
171 switch (Expr.Inst.Opcode) {
172 case wasm::WASM_OPCODE_I32_CONST:
173 Expr.Inst.Value.Int32 = readVarint32(Ctx);
174 break;
175 case wasm::WASM_OPCODE_I64_CONST:
176 Expr.Inst.Value.Int64 = readVarint64(Ctx);
177 break;
178 case wasm::WASM_OPCODE_F32_CONST:
179 Expr.Inst.Value.Float32 = readFloat32(Ctx);
180 break;
181 case wasm::WASM_OPCODE_F64_CONST:
182 Expr.Inst.Value.Float64 = readFloat64(Ctx);
183 break;
184 case wasm::WASM_OPCODE_GLOBAL_GET:
185 Expr.Inst.Value.Global = readULEB128(Ctx);
186 break;
187 case wasm::WASM_OPCODE_REF_NULL: {
188 wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
189 if (Ty != wasm::ValType::EXTERNREF) {
190 return make_error<GenericBinaryError>("invalid type for ref.null",
191 object_error::parse_failed);
192 }
193 break;
194 }
195 default:
196 Expr.Extended = true;
197 }
198
199 if (!Expr.Extended) {
200 uint8_t EndOpcode = readOpcode(Ctx);
201 if (EndOpcode != wasm::WASM_OPCODE_END)
202 Expr.Extended = true;
203 }
204
205 if (Expr.Extended) {
206 Ctx.Ptr = Start;
207 while (true) {
208 uint8_t Opcode = readOpcode(Ctx);
209 switch (Opcode) {
210 case wasm::WASM_OPCODE_I32_CONST:
211 case wasm::WASM_OPCODE_GLOBAL_GET:
212 case wasm::WASM_OPCODE_REF_NULL:
213 case wasm::WASM_OPCODE_I64_CONST:
214 case wasm::WASM_OPCODE_F32_CONST:
215 case wasm::WASM_OPCODE_F64_CONST:
216 readULEB128(Ctx);
217 break;
218 case wasm::WASM_OPCODE_I32_ADD:
219 case wasm::WASM_OPCODE_I32_SUB:
220 case wasm::WASM_OPCODE_I32_MUL:
221 case wasm::WASM_OPCODE_I64_ADD:
222 case wasm::WASM_OPCODE_I64_SUB:
223 case wasm::WASM_OPCODE_I64_MUL:
224 break;
225 case wasm::WASM_OPCODE_END:
226 Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
227 return Error::success();
228 default:
229 return make_error<GenericBinaryError>(
230 Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)),
231 object_error::parse_failed);
232 }
233 }
234 }
235
236 return Error::success();
237 }
238
readLimits(WasmObjectFile::ReadContext & Ctx)239 static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
240 wasm::WasmLimits Result;
241 Result.Flags = readVaruint32(Ctx);
242 Result.Minimum = readVaruint64(Ctx);
243 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
244 Result.Maximum = readVaruint64(Ctx);
245 return Result;
246 }
247
readTableType(WasmObjectFile::ReadContext & Ctx)248 static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
249 wasm::WasmTableType TableType;
250 TableType.ElemType = readUint8(Ctx);
251 TableType.Limits = readLimits(Ctx);
252 return TableType;
253 }
254
readSection(WasmSection & Section,WasmObjectFile::ReadContext & Ctx,WasmSectionOrderChecker & Checker)255 static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
256 WasmSectionOrderChecker &Checker) {
257 Section.Offset = Ctx.Ptr - Ctx.Start;
258 Section.Type = readUint8(Ctx);
259 LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
260 uint32_t Size = readVaruint32(Ctx);
261 if (Size == 0)
262 return make_error<StringError>("zero length section",
263 object_error::parse_failed);
264 if (Ctx.Ptr + Size > Ctx.End)
265 return make_error<StringError>("section too large",
266 object_error::parse_failed);
267 if (Section.Type == wasm::WASM_SEC_CUSTOM) {
268 WasmObjectFile::ReadContext SectionCtx;
269 SectionCtx.Start = Ctx.Ptr;
270 SectionCtx.Ptr = Ctx.Ptr;
271 SectionCtx.End = Ctx.Ptr + Size;
272
273 Section.Name = readString(SectionCtx);
274
275 uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
276 Ctx.Ptr += SectionNameSize;
277 Size -= SectionNameSize;
278 }
279
280 if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
281 return make_error<StringError>("out of order section type: " +
282 llvm::to_string(Section.Type),
283 object_error::parse_failed);
284 }
285
286 Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
287 Ctx.Ptr += Size;
288 return Error::success();
289 }
290
WasmObjectFile(MemoryBufferRef Buffer,Error & Err)291 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
292 : ObjectFile(Binary::ID_Wasm, Buffer) {
293 ErrorAsOutParameter ErrAsOutParam(&Err);
294 Header.Magic = getData().substr(0, 4);
295 if (Header.Magic != StringRef("\0asm", 4)) {
296 Err = make_error<StringError>("invalid magic number",
297 object_error::parse_failed);
298 return;
299 }
300
301 ReadContext Ctx;
302 Ctx.Start = getData().bytes_begin();
303 Ctx.Ptr = Ctx.Start + 4;
304 Ctx.End = Ctx.Start + getData().size();
305
306 if (Ctx.Ptr + 4 > Ctx.End) {
307 Err = make_error<StringError>("missing version number",
308 object_error::parse_failed);
309 return;
310 }
311
312 Header.Version = readUint32(Ctx);
313 if (Header.Version != wasm::WasmVersion) {
314 Err = make_error<StringError>("invalid version number: " +
315 Twine(Header.Version),
316 object_error::parse_failed);
317 return;
318 }
319
320 WasmSectionOrderChecker Checker;
321 while (Ctx.Ptr < Ctx.End) {
322 WasmSection Sec;
323 if ((Err = readSection(Sec, Ctx, Checker)))
324 return;
325 if ((Err = parseSection(Sec)))
326 return;
327
328 Sections.push_back(Sec);
329 }
330 }
331
parseSection(WasmSection & Sec)332 Error WasmObjectFile::parseSection(WasmSection &Sec) {
333 ReadContext Ctx;
334 Ctx.Start = Sec.Content.data();
335 Ctx.End = Ctx.Start + Sec.Content.size();
336 Ctx.Ptr = Ctx.Start;
337 switch (Sec.Type) {
338 case wasm::WASM_SEC_CUSTOM:
339 return parseCustomSection(Sec, Ctx);
340 case wasm::WASM_SEC_TYPE:
341 return parseTypeSection(Ctx);
342 case wasm::WASM_SEC_IMPORT:
343 return parseImportSection(Ctx);
344 case wasm::WASM_SEC_FUNCTION:
345 return parseFunctionSection(Ctx);
346 case wasm::WASM_SEC_TABLE:
347 return parseTableSection(Ctx);
348 case wasm::WASM_SEC_MEMORY:
349 return parseMemorySection(Ctx);
350 case wasm::WASM_SEC_TAG:
351 return parseTagSection(Ctx);
352 case wasm::WASM_SEC_GLOBAL:
353 return parseGlobalSection(Ctx);
354 case wasm::WASM_SEC_EXPORT:
355 return parseExportSection(Ctx);
356 case wasm::WASM_SEC_START:
357 return parseStartSection(Ctx);
358 case wasm::WASM_SEC_ELEM:
359 return parseElemSection(Ctx);
360 case wasm::WASM_SEC_CODE:
361 return parseCodeSection(Ctx);
362 case wasm::WASM_SEC_DATA:
363 return parseDataSection(Ctx);
364 case wasm::WASM_SEC_DATACOUNT:
365 return parseDataCountSection(Ctx);
366 default:
367 return make_error<GenericBinaryError>(
368 "invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
369 }
370 }
371
parseDylinkSection(ReadContext & Ctx)372 Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
373 // Legacy "dylink" section support.
374 // See parseDylink0Section for the current "dylink.0" section parsing.
375 HasDylinkSection = true;
376 DylinkInfo.MemorySize = readVaruint32(Ctx);
377 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
378 DylinkInfo.TableSize = readVaruint32(Ctx);
379 DylinkInfo.TableAlignment = readVaruint32(Ctx);
380 uint32_t Count = readVaruint32(Ctx);
381 while (Count--) {
382 DylinkInfo.Needed.push_back(readString(Ctx));
383 }
384
385 if (Ctx.Ptr != Ctx.End)
386 return make_error<GenericBinaryError>("dylink section ended prematurely",
387 object_error::parse_failed);
388 return Error::success();
389 }
390
parseDylink0Section(ReadContext & Ctx)391 Error WasmObjectFile::parseDylink0Section(ReadContext &Ctx) {
392 // See
393 // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
394 HasDylinkSection = true;
395
396 const uint8_t *OrigEnd = Ctx.End;
397 while (Ctx.Ptr < OrigEnd) {
398 Ctx.End = OrigEnd;
399 uint8_t Type = readUint8(Ctx);
400 uint32_t Size = readVaruint32(Ctx);
401 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
402 << "\n");
403 Ctx.End = Ctx.Ptr + Size;
404 uint32_t Count;
405 switch (Type) {
406 case wasm::WASM_DYLINK_MEM_INFO:
407 DylinkInfo.MemorySize = readVaruint32(Ctx);
408 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
409 DylinkInfo.TableSize = readVaruint32(Ctx);
410 DylinkInfo.TableAlignment = readVaruint32(Ctx);
411 break;
412 case wasm::WASM_DYLINK_NEEDED:
413 Count = readVaruint32(Ctx);
414 while (Count--) {
415 DylinkInfo.Needed.push_back(readString(Ctx));
416 }
417 break;
418 case wasm::WASM_DYLINK_EXPORT_INFO: {
419 uint32_t Count = readVaruint32(Ctx);
420 while (Count--) {
421 DylinkInfo.ExportInfo.push_back({readString(Ctx), readVaruint32(Ctx)});
422 }
423 break;
424 }
425 case wasm::WASM_DYLINK_IMPORT_INFO: {
426 uint32_t Count = readVaruint32(Ctx);
427 while (Count--) {
428 DylinkInfo.ImportInfo.push_back(
429 {readString(Ctx), readString(Ctx), readVaruint32(Ctx)});
430 }
431 break;
432 }
433 default:
434 LLVM_DEBUG(dbgs() << "unknown dylink.0 sub-section: " << Type << "\n");
435 Ctx.Ptr += Size;
436 break;
437 }
438 if (Ctx.Ptr != Ctx.End) {
439 return make_error<GenericBinaryError>(
440 "dylink.0 sub-section ended prematurely", object_error::parse_failed);
441 }
442 }
443
444 if (Ctx.Ptr != Ctx.End)
445 return make_error<GenericBinaryError>("dylink.0 section ended prematurely",
446 object_error::parse_failed);
447 return Error::success();
448 }
449
parseNameSection(ReadContext & Ctx)450 Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
451 llvm::DenseSet<uint64_t> SeenFunctions;
452 llvm::DenseSet<uint64_t> SeenGlobals;
453 llvm::DenseSet<uint64_t> SeenSegments;
454
455 while (Ctx.Ptr < Ctx.End) {
456 uint8_t Type = readUint8(Ctx);
457 uint32_t Size = readVaruint32(Ctx);
458 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
459 switch (Type) {
460 case wasm::WASM_NAMES_FUNCTION:
461 case wasm::WASM_NAMES_GLOBAL:
462 case wasm::WASM_NAMES_DATA_SEGMENT: {
463 uint32_t Count = readVaruint32(Ctx);
464 while (Count--) {
465 uint32_t Index = readVaruint32(Ctx);
466 StringRef Name = readString(Ctx);
467 wasm::NameType nameType = wasm::NameType::FUNCTION;
468 if (Type == wasm::WASM_NAMES_FUNCTION) {
469 if (!SeenFunctions.insert(Index).second)
470 return make_error<GenericBinaryError>(
471 "function named more than once", object_error::parse_failed);
472 if (!isValidFunctionIndex(Index) || Name.empty())
473 return make_error<GenericBinaryError>("invalid function name entry",
474 object_error::parse_failed);
475
476 if (isDefinedFunctionIndex(Index))
477 getDefinedFunction(Index).DebugName = Name;
478 } else if (Type == wasm::WASM_NAMES_GLOBAL) {
479 nameType = wasm::NameType::GLOBAL;
480 if (!SeenGlobals.insert(Index).second)
481 return make_error<GenericBinaryError>("global named more than once",
482 object_error::parse_failed);
483 if (!isValidGlobalIndex(Index) || Name.empty())
484 return make_error<GenericBinaryError>("invalid global name entry",
485 object_error::parse_failed);
486 } else {
487 nameType = wasm::NameType::DATA_SEGMENT;
488 if (!SeenSegments.insert(Index).second)
489 return make_error<GenericBinaryError>(
490 "segment named more than once", object_error::parse_failed);
491 if (Index > DataSegments.size())
492 return make_error<GenericBinaryError>("invalid data segment name entry",
493 object_error::parse_failed);
494 }
495 DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
496 }
497 break;
498 }
499 // Ignore local names for now
500 case wasm::WASM_NAMES_LOCAL:
501 default:
502 Ctx.Ptr += Size;
503 break;
504 }
505 if (Ctx.Ptr != SubSectionEnd)
506 return make_error<GenericBinaryError>(
507 "name sub-section ended prematurely", object_error::parse_failed);
508 }
509
510 if (Ctx.Ptr != Ctx.End)
511 return make_error<GenericBinaryError>("name section ended prematurely",
512 object_error::parse_failed);
513 return Error::success();
514 }
515
parseLinkingSection(ReadContext & Ctx)516 Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
517 HasLinkingSection = true;
518
519 LinkingData.Version = readVaruint32(Ctx);
520 if (LinkingData.Version != wasm::WasmMetadataVersion) {
521 return make_error<GenericBinaryError>(
522 "unexpected metadata version: " + Twine(LinkingData.Version) +
523 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
524 object_error::parse_failed);
525 }
526
527 const uint8_t *OrigEnd = Ctx.End;
528 while (Ctx.Ptr < OrigEnd) {
529 Ctx.End = OrigEnd;
530 uint8_t Type = readUint8(Ctx);
531 uint32_t Size = readVaruint32(Ctx);
532 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
533 << "\n");
534 Ctx.End = Ctx.Ptr + Size;
535 switch (Type) {
536 case wasm::WASM_SYMBOL_TABLE:
537 if (Error Err = parseLinkingSectionSymtab(Ctx))
538 return Err;
539 break;
540 case wasm::WASM_SEGMENT_INFO: {
541 uint32_t Count = readVaruint32(Ctx);
542 if (Count > DataSegments.size())
543 return make_error<GenericBinaryError>("too many segment names",
544 object_error::parse_failed);
545 for (uint32_t I = 0; I < Count; I++) {
546 DataSegments[I].Data.Name = readString(Ctx);
547 DataSegments[I].Data.Alignment = readVaruint32(Ctx);
548 DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
549 }
550 break;
551 }
552 case wasm::WASM_INIT_FUNCS: {
553 uint32_t Count = readVaruint32(Ctx);
554 LinkingData.InitFunctions.reserve(Count);
555 for (uint32_t I = 0; I < Count; I++) {
556 wasm::WasmInitFunc Init;
557 Init.Priority = readVaruint32(Ctx);
558 Init.Symbol = readVaruint32(Ctx);
559 if (!isValidFunctionSymbol(Init.Symbol))
560 return make_error<GenericBinaryError>("invalid function symbol: " +
561 Twine(Init.Symbol),
562 object_error::parse_failed);
563 LinkingData.InitFunctions.emplace_back(Init);
564 }
565 break;
566 }
567 case wasm::WASM_COMDAT_INFO:
568 if (Error Err = parseLinkingSectionComdat(Ctx))
569 return Err;
570 break;
571 default:
572 Ctx.Ptr += Size;
573 break;
574 }
575 if (Ctx.Ptr != Ctx.End)
576 return make_error<GenericBinaryError>(
577 "linking sub-section ended prematurely", object_error::parse_failed);
578 }
579 if (Ctx.Ptr != OrigEnd)
580 return make_error<GenericBinaryError>("linking section ended prematurely",
581 object_error::parse_failed);
582 return Error::success();
583 }
584
parseLinkingSectionSymtab(ReadContext & Ctx)585 Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
586 uint32_t Count = readVaruint32(Ctx);
587 LinkingData.SymbolTable.reserve(Count);
588 Symbols.reserve(Count);
589 StringSet<> SymbolNames;
590
591 std::vector<wasm::WasmImport *> ImportedGlobals;
592 std::vector<wasm::WasmImport *> ImportedFunctions;
593 std::vector<wasm::WasmImport *> ImportedTags;
594 std::vector<wasm::WasmImport *> ImportedTables;
595 ImportedGlobals.reserve(Imports.size());
596 ImportedFunctions.reserve(Imports.size());
597 ImportedTags.reserve(Imports.size());
598 ImportedTables.reserve(Imports.size());
599 for (auto &I : Imports) {
600 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
601 ImportedFunctions.emplace_back(&I);
602 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
603 ImportedGlobals.emplace_back(&I);
604 else if (I.Kind == wasm::WASM_EXTERNAL_TAG)
605 ImportedTags.emplace_back(&I);
606 else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
607 ImportedTables.emplace_back(&I);
608 }
609
610 while (Count--) {
611 wasm::WasmSymbolInfo Info;
612 const wasm::WasmSignature *Signature = nullptr;
613 const wasm::WasmGlobalType *GlobalType = nullptr;
614 const wasm::WasmTableType *TableType = nullptr;
615
616 Info.Kind = readUint8(Ctx);
617 Info.Flags = readVaruint32(Ctx);
618 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
619
620 switch (Info.Kind) {
621 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
622 Info.ElementIndex = readVaruint32(Ctx);
623 if (!isValidFunctionIndex(Info.ElementIndex) ||
624 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
625 return make_error<GenericBinaryError>("invalid function symbol index",
626 object_error::parse_failed);
627 if (IsDefined) {
628 Info.Name = readString(Ctx);
629 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
630 wasm::WasmFunction &Function = Functions[FuncIndex];
631 Signature = &Signatures[Function.SigIndex];
632 if (Function.SymbolName.empty())
633 Function.SymbolName = Info.Name;
634 } else {
635 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
636 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
637 Info.Name = readString(Ctx);
638 Info.ImportName = Import.Field;
639 } else {
640 Info.Name = Import.Field;
641 }
642 Signature = &Signatures[Import.SigIndex];
643 Info.ImportModule = Import.Module;
644 }
645 break;
646
647 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
648 Info.ElementIndex = readVaruint32(Ctx);
649 if (!isValidGlobalIndex(Info.ElementIndex) ||
650 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
651 return make_error<GenericBinaryError>("invalid global symbol index",
652 object_error::parse_failed);
653 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
654 wasm::WASM_SYMBOL_BINDING_WEAK)
655 return make_error<GenericBinaryError>("undefined weak global symbol",
656 object_error::parse_failed);
657 if (IsDefined) {
658 Info.Name = readString(Ctx);
659 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
660 wasm::WasmGlobal &Global = Globals[GlobalIndex];
661 GlobalType = &Global.Type;
662 if (Global.SymbolName.empty())
663 Global.SymbolName = Info.Name;
664 } else {
665 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
666 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
667 Info.Name = readString(Ctx);
668 Info.ImportName = Import.Field;
669 } else {
670 Info.Name = Import.Field;
671 }
672 GlobalType = &Import.Global;
673 Info.ImportModule = Import.Module;
674 }
675 break;
676
677 case wasm::WASM_SYMBOL_TYPE_TABLE:
678 Info.ElementIndex = readVaruint32(Ctx);
679 if (!isValidTableNumber(Info.ElementIndex) ||
680 IsDefined != isDefinedTableNumber(Info.ElementIndex))
681 return make_error<GenericBinaryError>("invalid table symbol index",
682 object_error::parse_failed);
683 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
684 wasm::WASM_SYMBOL_BINDING_WEAK)
685 return make_error<GenericBinaryError>("undefined weak table symbol",
686 object_error::parse_failed);
687 if (IsDefined) {
688 Info.Name = readString(Ctx);
689 unsigned TableNumber = Info.ElementIndex - NumImportedTables;
690 wasm::WasmTable &Table = Tables[TableNumber];
691 TableType = &Table.Type;
692 if (Table.SymbolName.empty())
693 Table.SymbolName = Info.Name;
694 } else {
695 wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
696 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
697 Info.Name = readString(Ctx);
698 Info.ImportName = Import.Field;
699 } else {
700 Info.Name = Import.Field;
701 }
702 TableType = &Import.Table;
703 Info.ImportModule = Import.Module;
704 }
705 break;
706
707 case wasm::WASM_SYMBOL_TYPE_DATA:
708 Info.Name = readString(Ctx);
709 if (IsDefined) {
710 auto Index = readVaruint32(Ctx);
711 if (Index >= DataSegments.size())
712 return make_error<GenericBinaryError>("invalid data symbol index",
713 object_error::parse_failed);
714 auto Offset = readVaruint64(Ctx);
715 auto Size = readVaruint64(Ctx);
716 size_t SegmentSize = DataSegments[Index].Data.Content.size();
717 if (Offset > SegmentSize)
718 return make_error<GenericBinaryError>(
719 "invalid data symbol offset: `" + Info.Name + "` (offset: " +
720 Twine(Offset) + " segment size: " + Twine(SegmentSize) + ")",
721 object_error::parse_failed);
722 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
723 }
724 break;
725
726 case wasm::WASM_SYMBOL_TYPE_SECTION: {
727 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
728 wasm::WASM_SYMBOL_BINDING_LOCAL)
729 return make_error<GenericBinaryError>(
730 "section symbols must have local binding",
731 object_error::parse_failed);
732 Info.ElementIndex = readVaruint32(Ctx);
733 // Use somewhat unique section name as symbol name.
734 StringRef SectionName = Sections[Info.ElementIndex].Name;
735 Info.Name = SectionName;
736 break;
737 }
738
739 case wasm::WASM_SYMBOL_TYPE_TAG: {
740 Info.ElementIndex = readVaruint32(Ctx);
741 if (!isValidTagIndex(Info.ElementIndex) ||
742 IsDefined != isDefinedTagIndex(Info.ElementIndex))
743 return make_error<GenericBinaryError>("invalid tag symbol index",
744 object_error::parse_failed);
745 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
746 wasm::WASM_SYMBOL_BINDING_WEAK)
747 return make_error<GenericBinaryError>("undefined weak global symbol",
748 object_error::parse_failed);
749 if (IsDefined) {
750 Info.Name = readString(Ctx);
751 unsigned TagIndex = Info.ElementIndex - NumImportedTags;
752 wasm::WasmTag &Tag = Tags[TagIndex];
753 Signature = &Signatures[Tag.SigIndex];
754 if (Tag.SymbolName.empty())
755 Tag.SymbolName = Info.Name;
756
757 } else {
758 wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
759 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
760 Info.Name = readString(Ctx);
761 Info.ImportName = Import.Field;
762 } else {
763 Info.Name = Import.Field;
764 }
765 Signature = &Signatures[Import.SigIndex];
766 Info.ImportModule = Import.Module;
767 }
768 break;
769 }
770
771 default:
772 return make_error<GenericBinaryError>("invalid symbol type: " +
773 Twine(unsigned(Info.Kind)),
774 object_error::parse_failed);
775 }
776
777 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
778 wasm::WASM_SYMBOL_BINDING_LOCAL &&
779 !SymbolNames.insert(Info.Name).second)
780 return make_error<GenericBinaryError>("duplicate symbol name " +
781 Twine(Info.Name),
782 object_error::parse_failed);
783 LinkingData.SymbolTable.emplace_back(Info);
784 Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType,
785 Signature);
786 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
787 }
788
789 return Error::success();
790 }
791
parseLinkingSectionComdat(ReadContext & Ctx)792 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
793 uint32_t ComdatCount = readVaruint32(Ctx);
794 StringSet<> ComdatSet;
795 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
796 StringRef Name = readString(Ctx);
797 if (Name.empty() || !ComdatSet.insert(Name).second)
798 return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
799 Twine(Name),
800 object_error::parse_failed);
801 LinkingData.Comdats.emplace_back(Name);
802 uint32_t Flags = readVaruint32(Ctx);
803 if (Flags != 0)
804 return make_error<GenericBinaryError>("unsupported COMDAT flags",
805 object_error::parse_failed);
806
807 uint32_t EntryCount = readVaruint32(Ctx);
808 while (EntryCount--) {
809 unsigned Kind = readVaruint32(Ctx);
810 unsigned Index = readVaruint32(Ctx);
811 switch (Kind) {
812 default:
813 return make_error<GenericBinaryError>("invalid COMDAT entry type",
814 object_error::parse_failed);
815 case wasm::WASM_COMDAT_DATA:
816 if (Index >= DataSegments.size())
817 return make_error<GenericBinaryError>(
818 "COMDAT data index out of range", object_error::parse_failed);
819 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
820 return make_error<GenericBinaryError>("data segment in two COMDATs",
821 object_error::parse_failed);
822 DataSegments[Index].Data.Comdat = ComdatIndex;
823 break;
824 case wasm::WASM_COMDAT_FUNCTION:
825 if (!isDefinedFunctionIndex(Index))
826 return make_error<GenericBinaryError>(
827 "COMDAT function index out of range", object_error::parse_failed);
828 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
829 return make_error<GenericBinaryError>("function in two COMDATs",
830 object_error::parse_failed);
831 getDefinedFunction(Index).Comdat = ComdatIndex;
832 break;
833 case wasm::WASM_COMDAT_SECTION:
834 if (Index >= Sections.size())
835 return make_error<GenericBinaryError>(
836 "COMDAT section index out of range", object_error::parse_failed);
837 if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
838 return make_error<GenericBinaryError>(
839 "non-custom section in a COMDAT", object_error::parse_failed);
840 Sections[Index].Comdat = ComdatIndex;
841 break;
842 }
843 }
844 }
845 return Error::success();
846 }
847
parseProducersSection(ReadContext & Ctx)848 Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
849 llvm::SmallSet<StringRef, 3> FieldsSeen;
850 uint32_t Fields = readVaruint32(Ctx);
851 for (size_t I = 0; I < Fields; ++I) {
852 StringRef FieldName = readString(Ctx);
853 if (!FieldsSeen.insert(FieldName).second)
854 return make_error<GenericBinaryError>(
855 "producers section does not have unique fields",
856 object_error::parse_failed);
857 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
858 if (FieldName == "language") {
859 ProducerVec = &ProducerInfo.Languages;
860 } else if (FieldName == "processed-by") {
861 ProducerVec = &ProducerInfo.Tools;
862 } else if (FieldName == "sdk") {
863 ProducerVec = &ProducerInfo.SDKs;
864 } else {
865 return make_error<GenericBinaryError>(
866 "producers section field is not named one of language, processed-by, "
867 "or sdk",
868 object_error::parse_failed);
869 }
870 uint32_t ValueCount = readVaruint32(Ctx);
871 llvm::SmallSet<StringRef, 8> ProducersSeen;
872 for (size_t J = 0; J < ValueCount; ++J) {
873 StringRef Name = readString(Ctx);
874 StringRef Version = readString(Ctx);
875 if (!ProducersSeen.insert(Name).second) {
876 return make_error<GenericBinaryError>(
877 "producers section contains repeated producer",
878 object_error::parse_failed);
879 }
880 ProducerVec->emplace_back(std::string(Name), std::string(Version));
881 }
882 }
883 if (Ctx.Ptr != Ctx.End)
884 return make_error<GenericBinaryError>("producers section ended prematurely",
885 object_error::parse_failed);
886 return Error::success();
887 }
888
parseTargetFeaturesSection(ReadContext & Ctx)889 Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
890 llvm::SmallSet<std::string, 8> FeaturesSeen;
891 uint32_t FeatureCount = readVaruint32(Ctx);
892 for (size_t I = 0; I < FeatureCount; ++I) {
893 wasm::WasmFeatureEntry Feature;
894 Feature.Prefix = readUint8(Ctx);
895 switch (Feature.Prefix) {
896 case wasm::WASM_FEATURE_PREFIX_USED:
897 case wasm::WASM_FEATURE_PREFIX_REQUIRED:
898 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
899 break;
900 default:
901 return make_error<GenericBinaryError>("unknown feature policy prefix",
902 object_error::parse_failed);
903 }
904 Feature.Name = std::string(readString(Ctx));
905 if (!FeaturesSeen.insert(Feature.Name).second)
906 return make_error<GenericBinaryError>(
907 "target features section contains repeated feature \"" +
908 Feature.Name + "\"",
909 object_error::parse_failed);
910 TargetFeatures.push_back(Feature);
911 }
912 if (Ctx.Ptr != Ctx.End)
913 return make_error<GenericBinaryError>(
914 "target features section ended prematurely",
915 object_error::parse_failed);
916 return Error::success();
917 }
918
parseRelocSection(StringRef Name,ReadContext & Ctx)919 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
920 uint32_t SectionIndex = readVaruint32(Ctx);
921 if (SectionIndex >= Sections.size())
922 return make_error<GenericBinaryError>("invalid section index",
923 object_error::parse_failed);
924 WasmSection &Section = Sections[SectionIndex];
925 uint32_t RelocCount = readVaruint32(Ctx);
926 uint32_t EndOffset = Section.Content.size();
927 uint32_t PreviousOffset = 0;
928 while (RelocCount--) {
929 wasm::WasmRelocation Reloc = {};
930 uint32_t type = readVaruint32(Ctx);
931 Reloc.Type = type;
932 Reloc.Offset = readVaruint32(Ctx);
933 if (Reloc.Offset < PreviousOffset)
934 return make_error<GenericBinaryError>("relocations not in offset order",
935 object_error::parse_failed);
936 PreviousOffset = Reloc.Offset;
937 Reloc.Index = readVaruint32(Ctx);
938 switch (type) {
939 case wasm::R_WASM_FUNCTION_INDEX_LEB:
940 case wasm::R_WASM_TABLE_INDEX_SLEB:
941 case wasm::R_WASM_TABLE_INDEX_SLEB64:
942 case wasm::R_WASM_TABLE_INDEX_I32:
943 case wasm::R_WASM_TABLE_INDEX_I64:
944 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
945 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
946 if (!isValidFunctionSymbol(Reloc.Index))
947 return make_error<GenericBinaryError>(
948 "invalid relocation function index", object_error::parse_failed);
949 break;
950 case wasm::R_WASM_TABLE_NUMBER_LEB:
951 if (!isValidTableSymbol(Reloc.Index))
952 return make_error<GenericBinaryError>("invalid relocation table index",
953 object_error::parse_failed);
954 break;
955 case wasm::R_WASM_TYPE_INDEX_LEB:
956 if (Reloc.Index >= Signatures.size())
957 return make_error<GenericBinaryError>("invalid relocation type index",
958 object_error::parse_failed);
959 break;
960 case wasm::R_WASM_GLOBAL_INDEX_LEB:
961 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
962 // symbols to refer to their GOT entries.
963 if (!isValidGlobalSymbol(Reloc.Index) &&
964 !isValidDataSymbol(Reloc.Index) &&
965 !isValidFunctionSymbol(Reloc.Index))
966 return make_error<GenericBinaryError>("invalid relocation global index",
967 object_error::parse_failed);
968 break;
969 case wasm::R_WASM_GLOBAL_INDEX_I32:
970 if (!isValidGlobalSymbol(Reloc.Index))
971 return make_error<GenericBinaryError>("invalid relocation global index",
972 object_error::parse_failed);
973 break;
974 case wasm::R_WASM_TAG_INDEX_LEB:
975 if (!isValidTagSymbol(Reloc.Index))
976 return make_error<GenericBinaryError>("invalid relocation tag index",
977 object_error::parse_failed);
978 break;
979 case wasm::R_WASM_MEMORY_ADDR_LEB:
980 case wasm::R_WASM_MEMORY_ADDR_SLEB:
981 case wasm::R_WASM_MEMORY_ADDR_I32:
982 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
983 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
984 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
985 if (!isValidDataSymbol(Reloc.Index))
986 return make_error<GenericBinaryError>("invalid relocation data index",
987 object_error::parse_failed);
988 Reloc.Addend = readVarint32(Ctx);
989 break;
990 case wasm::R_WASM_MEMORY_ADDR_LEB64:
991 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
992 case wasm::R_WASM_MEMORY_ADDR_I64:
993 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
994 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
995 if (!isValidDataSymbol(Reloc.Index))
996 return make_error<GenericBinaryError>("invalid relocation data index",
997 object_error::parse_failed);
998 Reloc.Addend = readVarint64(Ctx);
999 break;
1000 case wasm::R_WASM_FUNCTION_OFFSET_I32:
1001 if (!isValidFunctionSymbol(Reloc.Index))
1002 return make_error<GenericBinaryError>(
1003 "invalid relocation function index", object_error::parse_failed);
1004 Reloc.Addend = readVarint32(Ctx);
1005 break;
1006 case wasm::R_WASM_FUNCTION_OFFSET_I64:
1007 if (!isValidFunctionSymbol(Reloc.Index))
1008 return make_error<GenericBinaryError>(
1009 "invalid relocation function index", object_error::parse_failed);
1010 Reloc.Addend = readVarint64(Ctx);
1011 break;
1012 case wasm::R_WASM_SECTION_OFFSET_I32:
1013 if (!isValidSectionSymbol(Reloc.Index))
1014 return make_error<GenericBinaryError>(
1015 "invalid relocation section index", object_error::parse_failed);
1016 Reloc.Addend = readVarint32(Ctx);
1017 break;
1018 default:
1019 return make_error<GenericBinaryError>("invalid relocation type: " +
1020 Twine(type),
1021 object_error::parse_failed);
1022 }
1023
1024 // Relocations must fit inside the section, and must appear in order. They
1025 // also shouldn't overlap a function/element boundary, but we don't bother
1026 // to check that.
1027 uint64_t Size = 5;
1028 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
1029 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
1030 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
1031 Size = 10;
1032 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
1033 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
1034 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
1035 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
1036 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
1037 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
1038 Size = 4;
1039 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
1040 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
1041 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
1042 Size = 8;
1043 if (Reloc.Offset + Size > EndOffset)
1044 return make_error<GenericBinaryError>("invalid relocation offset",
1045 object_error::parse_failed);
1046
1047 Section.Relocations.push_back(Reloc);
1048 }
1049 if (Ctx.Ptr != Ctx.End)
1050 return make_error<GenericBinaryError>("reloc section ended prematurely",
1051 object_error::parse_failed);
1052 return Error::success();
1053 }
1054
parseCustomSection(WasmSection & Sec,ReadContext & Ctx)1055 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
1056 if (Sec.Name == "dylink") {
1057 if (Error Err = parseDylinkSection(Ctx))
1058 return Err;
1059 } else if (Sec.Name == "dylink.0") {
1060 if (Error Err = parseDylink0Section(Ctx))
1061 return Err;
1062 } else if (Sec.Name == "name") {
1063 if (Error Err = parseNameSection(Ctx))
1064 return Err;
1065 } else if (Sec.Name == "linking") {
1066 if (Error Err = parseLinkingSection(Ctx))
1067 return Err;
1068 } else if (Sec.Name == "producers") {
1069 if (Error Err = parseProducersSection(Ctx))
1070 return Err;
1071 } else if (Sec.Name == "target_features") {
1072 if (Error Err = parseTargetFeaturesSection(Ctx))
1073 return Err;
1074 } else if (Sec.Name.startswith("reloc.")) {
1075 if (Error Err = parseRelocSection(Sec.Name, Ctx))
1076 return Err;
1077 }
1078 return Error::success();
1079 }
1080
parseTypeSection(ReadContext & Ctx)1081 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1082 uint32_t Count = readVaruint32(Ctx);
1083 Signatures.reserve(Count);
1084 while (Count--) {
1085 wasm::WasmSignature Sig;
1086 uint8_t Form = readUint8(Ctx);
1087 if (Form != wasm::WASM_TYPE_FUNC) {
1088 return make_error<GenericBinaryError>("invalid signature type",
1089 object_error::parse_failed);
1090 }
1091 uint32_t ParamCount = readVaruint32(Ctx);
1092 Sig.Params.reserve(ParamCount);
1093 while (ParamCount--) {
1094 uint32_t ParamType = readUint8(Ctx);
1095 Sig.Params.push_back(wasm::ValType(ParamType));
1096 }
1097 uint32_t ReturnCount = readVaruint32(Ctx);
1098 while (ReturnCount--) {
1099 uint32_t ReturnType = readUint8(Ctx);
1100 Sig.Returns.push_back(wasm::ValType(ReturnType));
1101 }
1102 Signatures.push_back(std::move(Sig));
1103 }
1104 if (Ctx.Ptr != Ctx.End)
1105 return make_error<GenericBinaryError>("type section ended prematurely",
1106 object_error::parse_failed);
1107 return Error::success();
1108 }
1109
parseImportSection(ReadContext & Ctx)1110 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1111 uint32_t Count = readVaruint32(Ctx);
1112 uint32_t NumTypes = Signatures.size();
1113 Imports.reserve(Count);
1114 for (uint32_t I = 0; I < Count; I++) {
1115 wasm::WasmImport Im;
1116 Im.Module = readString(Ctx);
1117 Im.Field = readString(Ctx);
1118 Im.Kind = readUint8(Ctx);
1119 switch (Im.Kind) {
1120 case wasm::WASM_EXTERNAL_FUNCTION:
1121 NumImportedFunctions++;
1122 Im.SigIndex = readVaruint32(Ctx);
1123 if (Im.SigIndex >= NumTypes)
1124 return make_error<GenericBinaryError>("invalid function type",
1125 object_error::parse_failed);
1126 break;
1127 case wasm::WASM_EXTERNAL_GLOBAL:
1128 NumImportedGlobals++;
1129 Im.Global.Type = readUint8(Ctx);
1130 Im.Global.Mutable = readVaruint1(Ctx);
1131 break;
1132 case wasm::WASM_EXTERNAL_MEMORY:
1133 Im.Memory = readLimits(Ctx);
1134 if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1135 HasMemory64 = true;
1136 break;
1137 case wasm::WASM_EXTERNAL_TABLE: {
1138 Im.Table = readTableType(Ctx);
1139 NumImportedTables++;
1140 auto ElemType = Im.Table.ElemType;
1141 if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1142 ElemType != wasm::WASM_TYPE_EXTERNREF)
1143 return make_error<GenericBinaryError>("invalid table element type",
1144 object_error::parse_failed);
1145 break;
1146 }
1147 case wasm::WASM_EXTERNAL_TAG:
1148 NumImportedTags++;
1149 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1150 return make_error<GenericBinaryError>("invalid attribute",
1151 object_error::parse_failed);
1152 Im.SigIndex = readVaruint32(Ctx);
1153 if (Im.SigIndex >= NumTypes)
1154 return make_error<GenericBinaryError>("invalid tag type",
1155 object_error::parse_failed);
1156 break;
1157 default:
1158 return make_error<GenericBinaryError>("unexpected import kind",
1159 object_error::parse_failed);
1160 }
1161 Imports.push_back(Im);
1162 }
1163 if (Ctx.Ptr != Ctx.End)
1164 return make_error<GenericBinaryError>("import section ended prematurely",
1165 object_error::parse_failed);
1166 return Error::success();
1167 }
1168
parseFunctionSection(ReadContext & Ctx)1169 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1170 uint32_t Count = readVaruint32(Ctx);
1171 Functions.reserve(Count);
1172 uint32_t NumTypes = Signatures.size();
1173 while (Count--) {
1174 uint32_t Type = readVaruint32(Ctx);
1175 if (Type >= NumTypes)
1176 return make_error<GenericBinaryError>("invalid function type",
1177 object_error::parse_failed);
1178 wasm::WasmFunction F;
1179 F.SigIndex = Type;
1180 Functions.push_back(F);
1181 }
1182 if (Ctx.Ptr != Ctx.End)
1183 return make_error<GenericBinaryError>("function section ended prematurely",
1184 object_error::parse_failed);
1185 return Error::success();
1186 }
1187
parseTableSection(ReadContext & Ctx)1188 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1189 TableSection = Sections.size();
1190 uint32_t Count = readVaruint32(Ctx);
1191 Tables.reserve(Count);
1192 while (Count--) {
1193 wasm::WasmTable T;
1194 T.Type = readTableType(Ctx);
1195 T.Index = NumImportedTables + Tables.size();
1196 Tables.push_back(T);
1197 auto ElemType = Tables.back().Type.ElemType;
1198 if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1199 ElemType != wasm::WASM_TYPE_EXTERNREF) {
1200 return make_error<GenericBinaryError>("invalid table element type",
1201 object_error::parse_failed);
1202 }
1203 }
1204 if (Ctx.Ptr != Ctx.End)
1205 return make_error<GenericBinaryError>("table section ended prematurely",
1206 object_error::parse_failed);
1207 return Error::success();
1208 }
1209
parseMemorySection(ReadContext & Ctx)1210 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1211 uint32_t Count = readVaruint32(Ctx);
1212 Memories.reserve(Count);
1213 while (Count--) {
1214 auto Limits = readLimits(Ctx);
1215 if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1216 HasMemory64 = true;
1217 Memories.push_back(Limits);
1218 }
1219 if (Ctx.Ptr != Ctx.End)
1220 return make_error<GenericBinaryError>("memory section ended prematurely",
1221 object_error::parse_failed);
1222 return Error::success();
1223 }
1224
parseTagSection(ReadContext & Ctx)1225 Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
1226 TagSection = Sections.size();
1227 uint32_t Count = readVaruint32(Ctx);
1228 Tags.reserve(Count);
1229 uint32_t NumTypes = Signatures.size();
1230 while (Count--) {
1231 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1232 return make_error<GenericBinaryError>("invalid attribute",
1233 object_error::parse_failed);
1234 uint32_t Type = readVaruint32(Ctx);
1235 if (Type >= NumTypes)
1236 return make_error<GenericBinaryError>("invalid tag type",
1237 object_error::parse_failed);
1238 wasm::WasmTag Tag;
1239 Tag.Index = NumImportedTags + Tags.size();
1240 Tag.SigIndex = Type;
1241 Tags.push_back(Tag);
1242 }
1243
1244 if (Ctx.Ptr != Ctx.End)
1245 return make_error<GenericBinaryError>("tag section ended prematurely",
1246 object_error::parse_failed);
1247 return Error::success();
1248 }
1249
parseGlobalSection(ReadContext & Ctx)1250 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1251 GlobalSection = Sections.size();
1252 uint32_t Count = readVaruint32(Ctx);
1253 Globals.reserve(Count);
1254 while (Count--) {
1255 wasm::WasmGlobal Global;
1256 Global.Index = NumImportedGlobals + Globals.size();
1257 Global.Type.Type = readUint8(Ctx);
1258 Global.Type.Mutable = readVaruint1(Ctx);
1259 if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1260 return Err;
1261 Globals.push_back(Global);
1262 }
1263 if (Ctx.Ptr != Ctx.End)
1264 return make_error<GenericBinaryError>("global section ended prematurely",
1265 object_error::parse_failed);
1266 return Error::success();
1267 }
1268
parseExportSection(ReadContext & Ctx)1269 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1270 uint32_t Count = readVaruint32(Ctx);
1271 Exports.reserve(Count);
1272 for (uint32_t I = 0; I < Count; I++) {
1273 wasm::WasmExport Ex;
1274 Ex.Name = readString(Ctx);
1275 Ex.Kind = readUint8(Ctx);
1276 Ex.Index = readVaruint32(Ctx);
1277 switch (Ex.Kind) {
1278 case wasm::WASM_EXTERNAL_FUNCTION:
1279
1280 if (!isDefinedFunctionIndex(Ex.Index))
1281 return make_error<GenericBinaryError>("invalid function export",
1282 object_error::parse_failed);
1283 getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1284 break;
1285 case wasm::WASM_EXTERNAL_GLOBAL:
1286 if (!isValidGlobalIndex(Ex.Index))
1287 return make_error<GenericBinaryError>("invalid global export",
1288 object_error::parse_failed);
1289 break;
1290 case wasm::WASM_EXTERNAL_TAG:
1291 if (!isValidTagIndex(Ex.Index))
1292 return make_error<GenericBinaryError>("invalid tag export",
1293 object_error::parse_failed);
1294 break;
1295 case wasm::WASM_EXTERNAL_MEMORY:
1296 case wasm::WASM_EXTERNAL_TABLE:
1297 break;
1298 default:
1299 return make_error<GenericBinaryError>("unexpected export kind",
1300 object_error::parse_failed);
1301 }
1302 Exports.push_back(Ex);
1303 }
1304 if (Ctx.Ptr != Ctx.End)
1305 return make_error<GenericBinaryError>("export section ended prematurely",
1306 object_error::parse_failed);
1307 return Error::success();
1308 }
1309
isValidFunctionIndex(uint32_t Index) const1310 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1311 return Index < NumImportedFunctions + Functions.size();
1312 }
1313
isDefinedFunctionIndex(uint32_t Index) const1314 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1315 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1316 }
1317
isValidGlobalIndex(uint32_t Index) const1318 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1319 return Index < NumImportedGlobals + Globals.size();
1320 }
1321
isValidTableNumber(uint32_t Index) const1322 bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1323 return Index < NumImportedTables + Tables.size();
1324 }
1325
isDefinedGlobalIndex(uint32_t Index) const1326 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1327 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1328 }
1329
isDefinedTableNumber(uint32_t Index) const1330 bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1331 return Index >= NumImportedTables && isValidTableNumber(Index);
1332 }
1333
isValidTagIndex(uint32_t Index) const1334 bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
1335 return Index < NumImportedTags + Tags.size();
1336 }
1337
isDefinedTagIndex(uint32_t Index) const1338 bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
1339 return Index >= NumImportedTags && isValidTagIndex(Index);
1340 }
1341
isValidFunctionSymbol(uint32_t Index) const1342 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1343 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1344 }
1345
isValidTableSymbol(uint32_t Index) const1346 bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1347 return Index < Symbols.size() && Symbols[Index].isTypeTable();
1348 }
1349
isValidGlobalSymbol(uint32_t Index) const1350 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1351 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1352 }
1353
isValidTagSymbol(uint32_t Index) const1354 bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
1355 return Index < Symbols.size() && Symbols[Index].isTypeTag();
1356 }
1357
isValidDataSymbol(uint32_t Index) const1358 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1359 return Index < Symbols.size() && Symbols[Index].isTypeData();
1360 }
1361
isValidSectionSymbol(uint32_t Index) const1362 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1363 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1364 }
1365
getDefinedFunction(uint32_t Index)1366 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1367 assert(isDefinedFunctionIndex(Index));
1368 return Functions[Index - NumImportedFunctions];
1369 }
1370
1371 const wasm::WasmFunction &
getDefinedFunction(uint32_t Index) const1372 WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1373 assert(isDefinedFunctionIndex(Index));
1374 return Functions[Index - NumImportedFunctions];
1375 }
1376
getDefinedGlobal(uint32_t Index)1377 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1378 assert(isDefinedGlobalIndex(Index));
1379 return Globals[Index - NumImportedGlobals];
1380 }
1381
getDefinedTag(uint32_t Index)1382 wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
1383 assert(isDefinedTagIndex(Index));
1384 return Tags[Index - NumImportedTags];
1385 }
1386
parseStartSection(ReadContext & Ctx)1387 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1388 StartFunction = readVaruint32(Ctx);
1389 if (!isValidFunctionIndex(StartFunction))
1390 return make_error<GenericBinaryError>("invalid start function",
1391 object_error::parse_failed);
1392 return Error::success();
1393 }
1394
parseCodeSection(ReadContext & Ctx)1395 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1396 CodeSection = Sections.size();
1397 uint32_t FunctionCount = readVaruint32(Ctx);
1398 if (FunctionCount != Functions.size()) {
1399 return make_error<GenericBinaryError>("invalid function count",
1400 object_error::parse_failed);
1401 }
1402
1403 for (uint32_t i = 0; i < FunctionCount; i++) {
1404 wasm::WasmFunction& Function = Functions[i];
1405 const uint8_t *FunctionStart = Ctx.Ptr;
1406 uint32_t Size = readVaruint32(Ctx);
1407 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1408
1409 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1410 Function.Index = NumImportedFunctions + i;
1411 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1412 Function.Size = FunctionEnd - FunctionStart;
1413
1414 uint32_t NumLocalDecls = readVaruint32(Ctx);
1415 Function.Locals.reserve(NumLocalDecls);
1416 while (NumLocalDecls--) {
1417 wasm::WasmLocalDecl Decl;
1418 Decl.Count = readVaruint32(Ctx);
1419 Decl.Type = readUint8(Ctx);
1420 Function.Locals.push_back(Decl);
1421 }
1422
1423 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1424 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1425 // This will be set later when reading in the linking metadata section.
1426 Function.Comdat = UINT32_MAX;
1427 Ctx.Ptr += BodySize;
1428 assert(Ctx.Ptr == FunctionEnd);
1429 }
1430 if (Ctx.Ptr != Ctx.End)
1431 return make_error<GenericBinaryError>("code section ended prematurely",
1432 object_error::parse_failed);
1433 return Error::success();
1434 }
1435
parseElemSection(ReadContext & Ctx)1436 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1437 uint32_t Count = readVaruint32(Ctx);
1438 ElemSegments.reserve(Count);
1439 while (Count--) {
1440 wasm::WasmElemSegment Segment;
1441 Segment.Flags = readVaruint32(Ctx);
1442
1443 uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1444 wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1445 wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1446 if (Segment.Flags & ~SupportedFlags)
1447 return make_error<GenericBinaryError>(
1448 "Unsupported flags for element segment", object_error::parse_failed);
1449
1450 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
1451 Segment.TableNumber = readVaruint32(Ctx);
1452 else
1453 Segment.TableNumber = 0;
1454 if (!isValidTableNumber(Segment.TableNumber))
1455 return make_error<GenericBinaryError>("invalid TableNumber",
1456 object_error::parse_failed);
1457
1458 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
1459 Segment.Offset.Extended = false;
1460 Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1461 Segment.Offset.Inst.Value.Int32 = 0;
1462 } else {
1463 if (Error Err = readInitExpr(Segment.Offset, Ctx))
1464 return Err;
1465 }
1466
1467 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
1468 Segment.ElemKind = readUint8(Ctx);
1469 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1470 if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
1471 Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
1472 return make_error<GenericBinaryError>("invalid reference type",
1473 object_error::parse_failed);
1474 }
1475 } else {
1476 if (Segment.ElemKind != 0)
1477 return make_error<GenericBinaryError>("invalid elemtype",
1478 object_error::parse_failed);
1479 Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1480 }
1481 } else {
1482 Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1483 }
1484
1485 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
1486 return make_error<GenericBinaryError>(
1487 "elem segment init expressions not yet implemented",
1488 object_error::parse_failed);
1489
1490 uint32_t NumElems = readVaruint32(Ctx);
1491 while (NumElems--) {
1492 Segment.Functions.push_back(readVaruint32(Ctx));
1493 }
1494 ElemSegments.push_back(Segment);
1495 }
1496 if (Ctx.Ptr != Ctx.End)
1497 return make_error<GenericBinaryError>("elem section ended prematurely",
1498 object_error::parse_failed);
1499 return Error::success();
1500 }
1501
parseDataSection(ReadContext & Ctx)1502 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1503 DataSection = Sections.size();
1504 uint32_t Count = readVaruint32(Ctx);
1505 if (DataCount && Count != *DataCount)
1506 return make_error<GenericBinaryError>(
1507 "number of data segments does not match DataCount section");
1508 DataSegments.reserve(Count);
1509 while (Count--) {
1510 WasmSegment Segment;
1511 Segment.Data.InitFlags = readVaruint32(Ctx);
1512 Segment.Data.MemoryIndex =
1513 (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1514 ? readVaruint32(Ctx)
1515 : 0;
1516 if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1517 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1518 return Err;
1519 } else {
1520 Segment.Data.Offset.Extended = false;
1521 Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1522 Segment.Data.Offset.Inst.Value.Int32 = 0;
1523 }
1524 uint32_t Size = readVaruint32(Ctx);
1525 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1526 return make_error<GenericBinaryError>("invalid segment size",
1527 object_error::parse_failed);
1528 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1529 // The rest of these Data fields are set later, when reading in the linking
1530 // metadata section.
1531 Segment.Data.Alignment = 0;
1532 Segment.Data.LinkingFlags = 0;
1533 Segment.Data.Comdat = UINT32_MAX;
1534 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1535 Ctx.Ptr += Size;
1536 DataSegments.push_back(Segment);
1537 }
1538 if (Ctx.Ptr != Ctx.End)
1539 return make_error<GenericBinaryError>("data section ended prematurely",
1540 object_error::parse_failed);
1541 return Error::success();
1542 }
1543
parseDataCountSection(ReadContext & Ctx)1544 Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1545 DataCount = readVaruint32(Ctx);
1546 return Error::success();
1547 }
1548
getHeader() const1549 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1550 return Header;
1551 }
1552
moveSymbolNext(DataRefImpl & Symb) const1553 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1554
getSymbolFlags(DataRefImpl Symb) const1555 Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1556 uint32_t Result = SymbolRef::SF_None;
1557 const WasmSymbol &Sym = getWasmSymbol(Symb);
1558
1559 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1560 if (Sym.isBindingWeak())
1561 Result |= SymbolRef::SF_Weak;
1562 if (!Sym.isBindingLocal())
1563 Result |= SymbolRef::SF_Global;
1564 if (Sym.isHidden())
1565 Result |= SymbolRef::SF_Hidden;
1566 if (!Sym.isDefined())
1567 Result |= SymbolRef::SF_Undefined;
1568 if (Sym.isTypeFunction())
1569 Result |= SymbolRef::SF_Executable;
1570 return Result;
1571 }
1572
symbol_begin() const1573 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1574 DataRefImpl Ref;
1575 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1576 Ref.d.b = 0; // Symbol index
1577 return BasicSymbolRef(Ref, this);
1578 }
1579
symbol_end() const1580 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1581 DataRefImpl Ref;
1582 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1583 Ref.d.b = Symbols.size(); // Symbol index
1584 return BasicSymbolRef(Ref, this);
1585 }
1586
getWasmSymbol(const DataRefImpl & Symb) const1587 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1588 return Symbols[Symb.d.b];
1589 }
1590
getWasmSymbol(const SymbolRef & Symb) const1591 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1592 return getWasmSymbol(Symb.getRawDataRefImpl());
1593 }
1594
getSymbolName(DataRefImpl Symb) const1595 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1596 return getWasmSymbol(Symb).Info.Name;
1597 }
1598
getSymbolAddress(DataRefImpl Symb) const1599 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1600 auto &Sym = getWasmSymbol(Symb);
1601 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1602 isDefinedFunctionIndex(Sym.Info.ElementIndex))
1603 return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
1604 else
1605 return getSymbolValue(Symb);
1606 }
1607
getWasmSymbolValue(const WasmSymbol & Sym) const1608 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1609 switch (Sym.Info.Kind) {
1610 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1611 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1612 case wasm::WASM_SYMBOL_TYPE_TAG:
1613 case wasm::WASM_SYMBOL_TYPE_TABLE:
1614 return Sym.Info.ElementIndex;
1615 case wasm::WASM_SYMBOL_TYPE_DATA: {
1616 // The value of a data symbol is the segment offset, plus the symbol
1617 // offset within the segment.
1618 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1619 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1620 if (Segment.Offset.Extended) {
1621 llvm_unreachable("extended init exprs not supported");
1622 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1623 return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1624 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1625 return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1626 } else {
1627 llvm_unreachable("unknown init expr opcode");
1628 }
1629 }
1630 case wasm::WASM_SYMBOL_TYPE_SECTION:
1631 return 0;
1632 }
1633 llvm_unreachable("invalid symbol type");
1634 }
1635
getSymbolValueImpl(DataRefImpl Symb) const1636 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1637 return getWasmSymbolValue(getWasmSymbol(Symb));
1638 }
1639
getSymbolAlignment(DataRefImpl Symb) const1640 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1641 llvm_unreachable("not yet implemented");
1642 return 0;
1643 }
1644
getCommonSymbolSizeImpl(DataRefImpl Symb) const1645 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1646 llvm_unreachable("not yet implemented");
1647 return 0;
1648 }
1649
1650 Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const1651 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1652 const WasmSymbol &Sym = getWasmSymbol(Symb);
1653
1654 switch (Sym.Info.Kind) {
1655 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1656 return SymbolRef::ST_Function;
1657 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1658 return SymbolRef::ST_Other;
1659 case wasm::WASM_SYMBOL_TYPE_DATA:
1660 return SymbolRef::ST_Data;
1661 case wasm::WASM_SYMBOL_TYPE_SECTION:
1662 return SymbolRef::ST_Debug;
1663 case wasm::WASM_SYMBOL_TYPE_TAG:
1664 return SymbolRef::ST_Other;
1665 case wasm::WASM_SYMBOL_TYPE_TABLE:
1666 return SymbolRef::ST_Other;
1667 }
1668
1669 llvm_unreachable("unknown WasmSymbol::SymbolType");
1670 return SymbolRef::ST_Other;
1671 }
1672
1673 Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const1674 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1675 const WasmSymbol &Sym = getWasmSymbol(Symb);
1676 if (Sym.isUndefined())
1677 return section_end();
1678
1679 DataRefImpl Ref;
1680 Ref.d.a = getSymbolSectionIdImpl(Sym);
1681 return section_iterator(SectionRef(Ref, this));
1682 }
1683
getSymbolSectionId(SymbolRef Symb) const1684 uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1685 const WasmSymbol &Sym = getWasmSymbol(Symb);
1686 return getSymbolSectionIdImpl(Sym);
1687 }
1688
getSymbolSectionIdImpl(const WasmSymbol & Sym) const1689 uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1690 switch (Sym.Info.Kind) {
1691 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1692 return CodeSection;
1693 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1694 return GlobalSection;
1695 case wasm::WASM_SYMBOL_TYPE_DATA:
1696 return DataSection;
1697 case wasm::WASM_SYMBOL_TYPE_SECTION:
1698 return Sym.Info.ElementIndex;
1699 case wasm::WASM_SYMBOL_TYPE_TAG:
1700 return TagSection;
1701 case wasm::WASM_SYMBOL_TYPE_TABLE:
1702 return TableSection;
1703 default:
1704 llvm_unreachable("unknown WasmSymbol::SymbolType");
1705 }
1706 }
1707
moveSectionNext(DataRefImpl & Sec) const1708 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1709
getSectionName(DataRefImpl Sec) const1710 Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1711 const WasmSection &S = Sections[Sec.d.a];
1712 if (S.Type == wasm::WASM_SEC_CUSTOM)
1713 return S.Name;
1714 if (S.Type > wasm::WASM_SEC_LAST_KNOWN)
1715 return createStringError(object_error::invalid_section_index, "");
1716 return wasm::sectionTypeToString(S.Type);
1717 }
1718
getSectionAddress(DataRefImpl Sec) const1719 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1720
getSectionIndex(DataRefImpl Sec) const1721 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1722 return Sec.d.a;
1723 }
1724
getSectionSize(DataRefImpl Sec) const1725 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1726 const WasmSection &S = Sections[Sec.d.a];
1727 return S.Content.size();
1728 }
1729
1730 Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const1731 WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1732 const WasmSection &S = Sections[Sec.d.a];
1733 // This will never fail since wasm sections can never be empty (user-sections
1734 // must have a name and non-user sections each have a defined structure).
1735 return S.Content;
1736 }
1737
getSectionAlignment(DataRefImpl Sec) const1738 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1739 return 1;
1740 }
1741
isSectionCompressed(DataRefImpl Sec) const1742 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1743 return false;
1744 }
1745
isSectionText(DataRefImpl Sec) const1746 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1747 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1748 }
1749
isSectionData(DataRefImpl Sec) const1750 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1751 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1752 }
1753
isSectionBSS(DataRefImpl Sec) const1754 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1755
isSectionVirtual(DataRefImpl Sec) const1756 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1757
section_rel_begin(DataRefImpl Ref) const1758 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1759 DataRefImpl RelocRef;
1760 RelocRef.d.a = Ref.d.a;
1761 RelocRef.d.b = 0;
1762 return relocation_iterator(RelocationRef(RelocRef, this));
1763 }
1764
section_rel_end(DataRefImpl Ref) const1765 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1766 const WasmSection &Sec = getWasmSection(Ref);
1767 DataRefImpl RelocRef;
1768 RelocRef.d.a = Ref.d.a;
1769 RelocRef.d.b = Sec.Relocations.size();
1770 return relocation_iterator(RelocationRef(RelocRef, this));
1771 }
1772
moveRelocationNext(DataRefImpl & Rel) const1773 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1774
getRelocationOffset(DataRefImpl Ref) const1775 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1776 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1777 return Rel.Offset;
1778 }
1779
getRelocationSymbol(DataRefImpl Ref) const1780 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1781 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1782 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
1783 return symbol_end();
1784 DataRefImpl Sym;
1785 Sym.d.a = 1;
1786 Sym.d.b = Rel.Index;
1787 return symbol_iterator(SymbolRef(Sym, this));
1788 }
1789
getRelocationType(DataRefImpl Ref) const1790 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1791 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1792 return Rel.Type;
1793 }
1794
getRelocationTypeName(DataRefImpl Ref,SmallVectorImpl<char> & Result) const1795 void WasmObjectFile::getRelocationTypeName(
1796 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1797 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1798 StringRef Res = "Unknown";
1799
1800 #define WASM_RELOC(name, value) \
1801 case wasm::name: \
1802 Res = #name; \
1803 break;
1804
1805 switch (Rel.Type) {
1806 #include "llvm/BinaryFormat/WasmRelocs.def"
1807 }
1808
1809 #undef WASM_RELOC
1810
1811 Result.append(Res.begin(), Res.end());
1812 }
1813
section_begin() const1814 section_iterator WasmObjectFile::section_begin() const {
1815 DataRefImpl Ref;
1816 Ref.d.a = 0;
1817 return section_iterator(SectionRef(Ref, this));
1818 }
1819
section_end() const1820 section_iterator WasmObjectFile::section_end() const {
1821 DataRefImpl Ref;
1822 Ref.d.a = Sections.size();
1823 return section_iterator(SectionRef(Ref, this));
1824 }
1825
getBytesInAddress() const1826 uint8_t WasmObjectFile::getBytesInAddress() const {
1827 return HasMemory64 ? 8 : 4;
1828 }
1829
getFileFormatName() const1830 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1831
getArch() const1832 Triple::ArchType WasmObjectFile::getArch() const {
1833 return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
1834 }
1835
getFeatures() const1836 Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {
1837 return SubtargetFeatures();
1838 }
1839
isRelocatableObject() const1840 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1841
isSharedObject() const1842 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1843
getWasmSection(DataRefImpl Ref) const1844 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1845 assert(Ref.d.a < Sections.size());
1846 return Sections[Ref.d.a];
1847 }
1848
1849 const WasmSection &
getWasmSection(const SectionRef & Section) const1850 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1851 return getWasmSection(Section.getRawDataRefImpl());
1852 }
1853
1854 const wasm::WasmRelocation &
getWasmRelocation(const RelocationRef & Ref) const1855 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1856 return getWasmRelocation(Ref.getRawDataRefImpl());
1857 }
1858
1859 const wasm::WasmRelocation &
getWasmRelocation(DataRefImpl Ref) const1860 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1861 assert(Ref.d.a < Sections.size());
1862 const WasmSection &Sec = Sections[Ref.d.a];
1863 assert(Ref.d.b < Sec.Relocations.size());
1864 return Sec.Relocations[Ref.d.b];
1865 }
1866
getSectionOrder(unsigned ID,StringRef CustomSectionName)1867 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1868 StringRef CustomSectionName) {
1869 switch (ID) {
1870 case wasm::WASM_SEC_CUSTOM:
1871 return StringSwitch<unsigned>(CustomSectionName)
1872 .Case("dylink", WASM_SEC_ORDER_DYLINK)
1873 .Case("dylink.0", WASM_SEC_ORDER_DYLINK)
1874 .Case("linking", WASM_SEC_ORDER_LINKING)
1875 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1876 .Case("name", WASM_SEC_ORDER_NAME)
1877 .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1878 .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
1879 .Default(WASM_SEC_ORDER_NONE);
1880 case wasm::WASM_SEC_TYPE:
1881 return WASM_SEC_ORDER_TYPE;
1882 case wasm::WASM_SEC_IMPORT:
1883 return WASM_SEC_ORDER_IMPORT;
1884 case wasm::WASM_SEC_FUNCTION:
1885 return WASM_SEC_ORDER_FUNCTION;
1886 case wasm::WASM_SEC_TABLE:
1887 return WASM_SEC_ORDER_TABLE;
1888 case wasm::WASM_SEC_MEMORY:
1889 return WASM_SEC_ORDER_MEMORY;
1890 case wasm::WASM_SEC_GLOBAL:
1891 return WASM_SEC_ORDER_GLOBAL;
1892 case wasm::WASM_SEC_EXPORT:
1893 return WASM_SEC_ORDER_EXPORT;
1894 case wasm::WASM_SEC_START:
1895 return WASM_SEC_ORDER_START;
1896 case wasm::WASM_SEC_ELEM:
1897 return WASM_SEC_ORDER_ELEM;
1898 case wasm::WASM_SEC_CODE:
1899 return WASM_SEC_ORDER_CODE;
1900 case wasm::WASM_SEC_DATA:
1901 return WASM_SEC_ORDER_DATA;
1902 case wasm::WASM_SEC_DATACOUNT:
1903 return WASM_SEC_ORDER_DATACOUNT;
1904 case wasm::WASM_SEC_TAG:
1905 return WASM_SEC_ORDER_TAG;
1906 default:
1907 return WASM_SEC_ORDER_NONE;
1908 }
1909 }
1910
1911 // Represents the edges in a directed graph where any node B reachable from node
1912 // A is not allowed to appear before A in the section ordering, but may appear
1913 // afterward.
1914 int WasmSectionOrderChecker::DisallowedPredecessors
1915 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
1916 // WASM_SEC_ORDER_NONE
1917 {},
1918 // WASM_SEC_ORDER_TYPE
1919 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
1920 // WASM_SEC_ORDER_IMPORT
1921 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
1922 // WASM_SEC_ORDER_FUNCTION
1923 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
1924 // WASM_SEC_ORDER_TABLE
1925 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
1926 // WASM_SEC_ORDER_MEMORY
1927 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
1928 // WASM_SEC_ORDER_TAG
1929 {WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
1930 // WASM_SEC_ORDER_GLOBAL
1931 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
1932 // WASM_SEC_ORDER_EXPORT
1933 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
1934 // WASM_SEC_ORDER_START
1935 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
1936 // WASM_SEC_ORDER_ELEM
1937 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
1938 // WASM_SEC_ORDER_DATACOUNT
1939 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
1940 // WASM_SEC_ORDER_CODE
1941 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
1942 // WASM_SEC_ORDER_DATA
1943 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
1944
1945 // Custom Sections
1946 // WASM_SEC_ORDER_DYLINK
1947 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
1948 // WASM_SEC_ORDER_LINKING
1949 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
1950 // WASM_SEC_ORDER_RELOC (can be repeated)
1951 {},
1952 // WASM_SEC_ORDER_NAME
1953 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
1954 // WASM_SEC_ORDER_PRODUCERS
1955 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
1956 // WASM_SEC_ORDER_TARGET_FEATURES
1957 {WASM_SEC_ORDER_TARGET_FEATURES}};
1958
isValidSectionOrder(unsigned ID,StringRef CustomSectionName)1959 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1960 StringRef CustomSectionName) {
1961 int Order = getSectionOrder(ID, CustomSectionName);
1962 if (Order == WASM_SEC_ORDER_NONE)
1963 return true;
1964
1965 // Disallowed predecessors we need to check for
1966 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
1967
1968 // Keep track of completed checks to avoid repeating work
1969 bool Checked[WASM_NUM_SEC_ORDERS] = {};
1970
1971 int Curr = Order;
1972 while (true) {
1973 // Add new disallowed predecessors to work list
1974 for (size_t I = 0;; ++I) {
1975 int Next = DisallowedPredecessors[Curr][I];
1976 if (Next == WASM_SEC_ORDER_NONE)
1977 break;
1978 if (Checked[Next])
1979 continue;
1980 WorkList.push_back(Next);
1981 Checked[Next] = true;
1982 }
1983
1984 if (WorkList.empty())
1985 break;
1986
1987 // Consider next disallowed predecessor
1988 Curr = WorkList.pop_back_val();
1989 if (Seen[Curr])
1990 return false;
1991 }
1992
1993 // Have not seen any disallowed predecessors
1994 Seen[Order] = true;
1995 return true;
1996 }
1997