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 if (!Import.Module.empty()) {
644 Info.ImportModule = Import.Module;
645 }
646 }
647 break;
648
649 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
650 Info.ElementIndex = readVaruint32(Ctx);
651 if (!isValidGlobalIndex(Info.ElementIndex) ||
652 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
653 return make_error<GenericBinaryError>("invalid global symbol index",
654 object_error::parse_failed);
655 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
656 wasm::WASM_SYMBOL_BINDING_WEAK)
657 return make_error<GenericBinaryError>("undefined weak global symbol",
658 object_error::parse_failed);
659 if (IsDefined) {
660 Info.Name = readString(Ctx);
661 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
662 wasm::WasmGlobal &Global = Globals[GlobalIndex];
663 GlobalType = &Global.Type;
664 if (Global.SymbolName.empty())
665 Global.SymbolName = Info.Name;
666 } else {
667 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
668 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
669 Info.Name = readString(Ctx);
670 Info.ImportName = Import.Field;
671 } else {
672 Info.Name = Import.Field;
673 }
674 GlobalType = &Import.Global;
675 if (!Import.Module.empty()) {
676 Info.ImportModule = Import.Module;
677 }
678 }
679 break;
680
681 case wasm::WASM_SYMBOL_TYPE_TABLE:
682 Info.ElementIndex = readVaruint32(Ctx);
683 if (!isValidTableNumber(Info.ElementIndex) ||
684 IsDefined != isDefinedTableNumber(Info.ElementIndex))
685 return make_error<GenericBinaryError>("invalid table symbol index",
686 object_error::parse_failed);
687 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
688 wasm::WASM_SYMBOL_BINDING_WEAK)
689 return make_error<GenericBinaryError>("undefined weak table symbol",
690 object_error::parse_failed);
691 if (IsDefined) {
692 Info.Name = readString(Ctx);
693 unsigned TableNumber = Info.ElementIndex - NumImportedTables;
694 wasm::WasmTable &Table = Tables[TableNumber];
695 TableType = &Table.Type;
696 if (Table.SymbolName.empty())
697 Table.SymbolName = Info.Name;
698 } else {
699 wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
700 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
701 Info.Name = readString(Ctx);
702 Info.ImportName = Import.Field;
703 } else {
704 Info.Name = Import.Field;
705 }
706 TableType = &Import.Table;
707 if (!Import.Module.empty()) {
708 Info.ImportModule = Import.Module;
709 }
710 }
711 break;
712
713 case wasm::WASM_SYMBOL_TYPE_DATA:
714 Info.Name = readString(Ctx);
715 if (IsDefined) {
716 auto Index = readVaruint32(Ctx);
717 if (Index >= DataSegments.size())
718 return make_error<GenericBinaryError>("invalid data symbol index",
719 object_error::parse_failed);
720 auto Offset = readVaruint64(Ctx);
721 auto Size = readVaruint64(Ctx);
722 size_t SegmentSize = DataSegments[Index].Data.Content.size();
723 if (Offset > SegmentSize)
724 return make_error<GenericBinaryError>(
725 "invalid data symbol offset: `" + Info.Name + "` (offset: " +
726 Twine(Offset) + " segment size: " + Twine(SegmentSize) + ")",
727 object_error::parse_failed);
728 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
729 }
730 break;
731
732 case wasm::WASM_SYMBOL_TYPE_SECTION: {
733 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
734 wasm::WASM_SYMBOL_BINDING_LOCAL)
735 return make_error<GenericBinaryError>(
736 "section symbols must have local binding",
737 object_error::parse_failed);
738 Info.ElementIndex = readVaruint32(Ctx);
739 // Use somewhat unique section name as symbol name.
740 StringRef SectionName = Sections[Info.ElementIndex].Name;
741 Info.Name = SectionName;
742 break;
743 }
744
745 case wasm::WASM_SYMBOL_TYPE_TAG: {
746 Info.ElementIndex = readVaruint32(Ctx);
747 if (!isValidTagIndex(Info.ElementIndex) ||
748 IsDefined != isDefinedTagIndex(Info.ElementIndex))
749 return make_error<GenericBinaryError>("invalid tag symbol index",
750 object_error::parse_failed);
751 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
752 wasm::WASM_SYMBOL_BINDING_WEAK)
753 return make_error<GenericBinaryError>("undefined weak global symbol",
754 object_error::parse_failed);
755 if (IsDefined) {
756 Info.Name = readString(Ctx);
757 unsigned TagIndex = Info.ElementIndex - NumImportedTags;
758 wasm::WasmTag &Tag = Tags[TagIndex];
759 Signature = &Signatures[Tag.SigIndex];
760 if (Tag.SymbolName.empty())
761 Tag.SymbolName = Info.Name;
762
763 } else {
764 wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
765 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
766 Info.Name = readString(Ctx);
767 Info.ImportName = Import.Field;
768 } else {
769 Info.Name = Import.Field;
770 }
771 Signature = &Signatures[Import.SigIndex];
772 if (!Import.Module.empty()) {
773 Info.ImportModule = Import.Module;
774 }
775 }
776 break;
777 }
778
779 default:
780 return make_error<GenericBinaryError>("invalid symbol type: " +
781 Twine(unsigned(Info.Kind)),
782 object_error::parse_failed);
783 }
784
785 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
786 wasm::WASM_SYMBOL_BINDING_LOCAL &&
787 !SymbolNames.insert(Info.Name).second)
788 return make_error<GenericBinaryError>("duplicate symbol name " +
789 Twine(Info.Name),
790 object_error::parse_failed);
791 LinkingData.SymbolTable.emplace_back(Info);
792 Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType,
793 Signature);
794 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
795 }
796
797 return Error::success();
798 }
799
parseLinkingSectionComdat(ReadContext & Ctx)800 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
801 uint32_t ComdatCount = readVaruint32(Ctx);
802 StringSet<> ComdatSet;
803 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
804 StringRef Name = readString(Ctx);
805 if (Name.empty() || !ComdatSet.insert(Name).second)
806 return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
807 Twine(Name),
808 object_error::parse_failed);
809 LinkingData.Comdats.emplace_back(Name);
810 uint32_t Flags = readVaruint32(Ctx);
811 if (Flags != 0)
812 return make_error<GenericBinaryError>("unsupported COMDAT flags",
813 object_error::parse_failed);
814
815 uint32_t EntryCount = readVaruint32(Ctx);
816 while (EntryCount--) {
817 unsigned Kind = readVaruint32(Ctx);
818 unsigned Index = readVaruint32(Ctx);
819 switch (Kind) {
820 default:
821 return make_error<GenericBinaryError>("invalid COMDAT entry type",
822 object_error::parse_failed);
823 case wasm::WASM_COMDAT_DATA:
824 if (Index >= DataSegments.size())
825 return make_error<GenericBinaryError>(
826 "COMDAT data index out of range", object_error::parse_failed);
827 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
828 return make_error<GenericBinaryError>("data segment in two COMDATs",
829 object_error::parse_failed);
830 DataSegments[Index].Data.Comdat = ComdatIndex;
831 break;
832 case wasm::WASM_COMDAT_FUNCTION:
833 if (!isDefinedFunctionIndex(Index))
834 return make_error<GenericBinaryError>(
835 "COMDAT function index out of range", object_error::parse_failed);
836 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
837 return make_error<GenericBinaryError>("function in two COMDATs",
838 object_error::parse_failed);
839 getDefinedFunction(Index).Comdat = ComdatIndex;
840 break;
841 case wasm::WASM_COMDAT_SECTION:
842 if (Index >= Sections.size())
843 return make_error<GenericBinaryError>(
844 "COMDAT section index out of range", object_error::parse_failed);
845 if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
846 return make_error<GenericBinaryError>(
847 "non-custom section in a COMDAT", object_error::parse_failed);
848 Sections[Index].Comdat = ComdatIndex;
849 break;
850 }
851 }
852 }
853 return Error::success();
854 }
855
parseProducersSection(ReadContext & Ctx)856 Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
857 llvm::SmallSet<StringRef, 3> FieldsSeen;
858 uint32_t Fields = readVaruint32(Ctx);
859 for (size_t I = 0; I < Fields; ++I) {
860 StringRef FieldName = readString(Ctx);
861 if (!FieldsSeen.insert(FieldName).second)
862 return make_error<GenericBinaryError>(
863 "producers section does not have unique fields",
864 object_error::parse_failed);
865 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
866 if (FieldName == "language") {
867 ProducerVec = &ProducerInfo.Languages;
868 } else if (FieldName == "processed-by") {
869 ProducerVec = &ProducerInfo.Tools;
870 } else if (FieldName == "sdk") {
871 ProducerVec = &ProducerInfo.SDKs;
872 } else {
873 return make_error<GenericBinaryError>(
874 "producers section field is not named one of language, processed-by, "
875 "or sdk",
876 object_error::parse_failed);
877 }
878 uint32_t ValueCount = readVaruint32(Ctx);
879 llvm::SmallSet<StringRef, 8> ProducersSeen;
880 for (size_t J = 0; J < ValueCount; ++J) {
881 StringRef Name = readString(Ctx);
882 StringRef Version = readString(Ctx);
883 if (!ProducersSeen.insert(Name).second) {
884 return make_error<GenericBinaryError>(
885 "producers section contains repeated producer",
886 object_error::parse_failed);
887 }
888 ProducerVec->emplace_back(std::string(Name), std::string(Version));
889 }
890 }
891 if (Ctx.Ptr != Ctx.End)
892 return make_error<GenericBinaryError>("producers section ended prematurely",
893 object_error::parse_failed);
894 return Error::success();
895 }
896
parseTargetFeaturesSection(ReadContext & Ctx)897 Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
898 llvm::SmallSet<std::string, 8> FeaturesSeen;
899 uint32_t FeatureCount = readVaruint32(Ctx);
900 for (size_t I = 0; I < FeatureCount; ++I) {
901 wasm::WasmFeatureEntry Feature;
902 Feature.Prefix = readUint8(Ctx);
903 switch (Feature.Prefix) {
904 case wasm::WASM_FEATURE_PREFIX_USED:
905 case wasm::WASM_FEATURE_PREFIX_REQUIRED:
906 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
907 break;
908 default:
909 return make_error<GenericBinaryError>("unknown feature policy prefix",
910 object_error::parse_failed);
911 }
912 Feature.Name = std::string(readString(Ctx));
913 if (!FeaturesSeen.insert(Feature.Name).second)
914 return make_error<GenericBinaryError>(
915 "target features section contains repeated feature \"" +
916 Feature.Name + "\"",
917 object_error::parse_failed);
918 TargetFeatures.push_back(Feature);
919 }
920 if (Ctx.Ptr != Ctx.End)
921 return make_error<GenericBinaryError>(
922 "target features section ended prematurely",
923 object_error::parse_failed);
924 return Error::success();
925 }
926
parseRelocSection(StringRef Name,ReadContext & Ctx)927 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
928 uint32_t SectionIndex = readVaruint32(Ctx);
929 if (SectionIndex >= Sections.size())
930 return make_error<GenericBinaryError>("invalid section index",
931 object_error::parse_failed);
932 WasmSection &Section = Sections[SectionIndex];
933 uint32_t RelocCount = readVaruint32(Ctx);
934 uint32_t EndOffset = Section.Content.size();
935 uint32_t PreviousOffset = 0;
936 while (RelocCount--) {
937 wasm::WasmRelocation Reloc = {};
938 uint32_t type = readVaruint32(Ctx);
939 Reloc.Type = type;
940 Reloc.Offset = readVaruint32(Ctx);
941 if (Reloc.Offset < PreviousOffset)
942 return make_error<GenericBinaryError>("relocations not in offset order",
943 object_error::parse_failed);
944 PreviousOffset = Reloc.Offset;
945 Reloc.Index = readVaruint32(Ctx);
946 switch (type) {
947 case wasm::R_WASM_FUNCTION_INDEX_LEB:
948 case wasm::R_WASM_TABLE_INDEX_SLEB:
949 case wasm::R_WASM_TABLE_INDEX_SLEB64:
950 case wasm::R_WASM_TABLE_INDEX_I32:
951 case wasm::R_WASM_TABLE_INDEX_I64:
952 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
953 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
954 if (!isValidFunctionSymbol(Reloc.Index))
955 return make_error<GenericBinaryError>(
956 "invalid relocation function index", object_error::parse_failed);
957 break;
958 case wasm::R_WASM_TABLE_NUMBER_LEB:
959 if (!isValidTableSymbol(Reloc.Index))
960 return make_error<GenericBinaryError>("invalid relocation table index",
961 object_error::parse_failed);
962 break;
963 case wasm::R_WASM_TYPE_INDEX_LEB:
964 if (Reloc.Index >= Signatures.size())
965 return make_error<GenericBinaryError>("invalid relocation type index",
966 object_error::parse_failed);
967 break;
968 case wasm::R_WASM_GLOBAL_INDEX_LEB:
969 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
970 // symbols to refer to their GOT entries.
971 if (!isValidGlobalSymbol(Reloc.Index) &&
972 !isValidDataSymbol(Reloc.Index) &&
973 !isValidFunctionSymbol(Reloc.Index))
974 return make_error<GenericBinaryError>("invalid relocation global index",
975 object_error::parse_failed);
976 break;
977 case wasm::R_WASM_GLOBAL_INDEX_I32:
978 if (!isValidGlobalSymbol(Reloc.Index))
979 return make_error<GenericBinaryError>("invalid relocation global index",
980 object_error::parse_failed);
981 break;
982 case wasm::R_WASM_TAG_INDEX_LEB:
983 if (!isValidTagSymbol(Reloc.Index))
984 return make_error<GenericBinaryError>("invalid relocation tag index",
985 object_error::parse_failed);
986 break;
987 case wasm::R_WASM_MEMORY_ADDR_LEB:
988 case wasm::R_WASM_MEMORY_ADDR_SLEB:
989 case wasm::R_WASM_MEMORY_ADDR_I32:
990 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
991 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
992 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
993 if (!isValidDataSymbol(Reloc.Index))
994 return make_error<GenericBinaryError>("invalid relocation data index",
995 object_error::parse_failed);
996 Reloc.Addend = readVarint32(Ctx);
997 break;
998 case wasm::R_WASM_MEMORY_ADDR_LEB64:
999 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
1000 case wasm::R_WASM_MEMORY_ADDR_I64:
1001 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
1002 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
1003 if (!isValidDataSymbol(Reloc.Index))
1004 return make_error<GenericBinaryError>("invalid relocation data index",
1005 object_error::parse_failed);
1006 Reloc.Addend = readVarint64(Ctx);
1007 break;
1008 case wasm::R_WASM_FUNCTION_OFFSET_I32:
1009 if (!isValidFunctionSymbol(Reloc.Index))
1010 return make_error<GenericBinaryError>(
1011 "invalid relocation function index", object_error::parse_failed);
1012 Reloc.Addend = readVarint32(Ctx);
1013 break;
1014 case wasm::R_WASM_FUNCTION_OFFSET_I64:
1015 if (!isValidFunctionSymbol(Reloc.Index))
1016 return make_error<GenericBinaryError>(
1017 "invalid relocation function index", object_error::parse_failed);
1018 Reloc.Addend = readVarint64(Ctx);
1019 break;
1020 case wasm::R_WASM_SECTION_OFFSET_I32:
1021 if (!isValidSectionSymbol(Reloc.Index))
1022 return make_error<GenericBinaryError>(
1023 "invalid relocation section index", object_error::parse_failed);
1024 Reloc.Addend = readVarint32(Ctx);
1025 break;
1026 default:
1027 return make_error<GenericBinaryError>("invalid relocation type: " +
1028 Twine(type),
1029 object_error::parse_failed);
1030 }
1031
1032 // Relocations must fit inside the section, and must appear in order. They
1033 // also shouldn't overlap a function/element boundary, but we don't bother
1034 // to check that.
1035 uint64_t Size = 5;
1036 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
1037 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
1038 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
1039 Size = 10;
1040 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
1041 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
1042 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
1043 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
1044 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
1045 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
1046 Size = 4;
1047 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
1048 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
1049 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
1050 Size = 8;
1051 if (Reloc.Offset + Size > EndOffset)
1052 return make_error<GenericBinaryError>("invalid relocation offset",
1053 object_error::parse_failed);
1054
1055 Section.Relocations.push_back(Reloc);
1056 }
1057 if (Ctx.Ptr != Ctx.End)
1058 return make_error<GenericBinaryError>("reloc section ended prematurely",
1059 object_error::parse_failed);
1060 return Error::success();
1061 }
1062
parseCustomSection(WasmSection & Sec,ReadContext & Ctx)1063 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
1064 if (Sec.Name == "dylink") {
1065 if (Error Err = parseDylinkSection(Ctx))
1066 return Err;
1067 } else if (Sec.Name == "dylink.0") {
1068 if (Error Err = parseDylink0Section(Ctx))
1069 return Err;
1070 } else if (Sec.Name == "name") {
1071 if (Error Err = parseNameSection(Ctx))
1072 return Err;
1073 } else if (Sec.Name == "linking") {
1074 if (Error Err = parseLinkingSection(Ctx))
1075 return Err;
1076 } else if (Sec.Name == "producers") {
1077 if (Error Err = parseProducersSection(Ctx))
1078 return Err;
1079 } else if (Sec.Name == "target_features") {
1080 if (Error Err = parseTargetFeaturesSection(Ctx))
1081 return Err;
1082 } else if (Sec.Name.startswith("reloc.")) {
1083 if (Error Err = parseRelocSection(Sec.Name, Ctx))
1084 return Err;
1085 }
1086 return Error::success();
1087 }
1088
parseTypeSection(ReadContext & Ctx)1089 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1090 uint32_t Count = readVaruint32(Ctx);
1091 Signatures.reserve(Count);
1092 while (Count--) {
1093 wasm::WasmSignature Sig;
1094 uint8_t Form = readUint8(Ctx);
1095 if (Form != wasm::WASM_TYPE_FUNC) {
1096 return make_error<GenericBinaryError>("invalid signature type",
1097 object_error::parse_failed);
1098 }
1099 uint32_t ParamCount = readVaruint32(Ctx);
1100 Sig.Params.reserve(ParamCount);
1101 while (ParamCount--) {
1102 uint32_t ParamType = readUint8(Ctx);
1103 Sig.Params.push_back(wasm::ValType(ParamType));
1104 }
1105 uint32_t ReturnCount = readVaruint32(Ctx);
1106 while (ReturnCount--) {
1107 uint32_t ReturnType = readUint8(Ctx);
1108 Sig.Returns.push_back(wasm::ValType(ReturnType));
1109 }
1110 Signatures.push_back(std::move(Sig));
1111 }
1112 if (Ctx.Ptr != Ctx.End)
1113 return make_error<GenericBinaryError>("type section ended prematurely",
1114 object_error::parse_failed);
1115 return Error::success();
1116 }
1117
parseImportSection(ReadContext & Ctx)1118 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1119 uint32_t Count = readVaruint32(Ctx);
1120 uint32_t NumTypes = Signatures.size();
1121 Imports.reserve(Count);
1122 for (uint32_t I = 0; I < Count; I++) {
1123 wasm::WasmImport Im;
1124 Im.Module = readString(Ctx);
1125 Im.Field = readString(Ctx);
1126 Im.Kind = readUint8(Ctx);
1127 switch (Im.Kind) {
1128 case wasm::WASM_EXTERNAL_FUNCTION:
1129 NumImportedFunctions++;
1130 Im.SigIndex = readVaruint32(Ctx);
1131 if (Im.SigIndex >= NumTypes)
1132 return make_error<GenericBinaryError>("invalid function type",
1133 object_error::parse_failed);
1134 break;
1135 case wasm::WASM_EXTERNAL_GLOBAL:
1136 NumImportedGlobals++;
1137 Im.Global.Type = readUint8(Ctx);
1138 Im.Global.Mutable = readVaruint1(Ctx);
1139 break;
1140 case wasm::WASM_EXTERNAL_MEMORY:
1141 Im.Memory = readLimits(Ctx);
1142 if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1143 HasMemory64 = true;
1144 break;
1145 case wasm::WASM_EXTERNAL_TABLE: {
1146 Im.Table = readTableType(Ctx);
1147 NumImportedTables++;
1148 auto ElemType = Im.Table.ElemType;
1149 if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1150 ElemType != wasm::WASM_TYPE_EXTERNREF)
1151 return make_error<GenericBinaryError>("invalid table element type",
1152 object_error::parse_failed);
1153 break;
1154 }
1155 case wasm::WASM_EXTERNAL_TAG:
1156 NumImportedTags++;
1157 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1158 return make_error<GenericBinaryError>("invalid attribute",
1159 object_error::parse_failed);
1160 Im.SigIndex = readVaruint32(Ctx);
1161 if (Im.SigIndex >= NumTypes)
1162 return make_error<GenericBinaryError>("invalid tag type",
1163 object_error::parse_failed);
1164 break;
1165 default:
1166 return make_error<GenericBinaryError>("unexpected import kind",
1167 object_error::parse_failed);
1168 }
1169 Imports.push_back(Im);
1170 }
1171 if (Ctx.Ptr != Ctx.End)
1172 return make_error<GenericBinaryError>("import section ended prematurely",
1173 object_error::parse_failed);
1174 return Error::success();
1175 }
1176
parseFunctionSection(ReadContext & Ctx)1177 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1178 uint32_t Count = readVaruint32(Ctx);
1179 Functions.reserve(Count);
1180 uint32_t NumTypes = Signatures.size();
1181 while (Count--) {
1182 uint32_t Type = readVaruint32(Ctx);
1183 if (Type >= NumTypes)
1184 return make_error<GenericBinaryError>("invalid function type",
1185 object_error::parse_failed);
1186 wasm::WasmFunction F;
1187 F.SigIndex = Type;
1188 Functions.push_back(F);
1189 }
1190 if (Ctx.Ptr != Ctx.End)
1191 return make_error<GenericBinaryError>("function section ended prematurely",
1192 object_error::parse_failed);
1193 return Error::success();
1194 }
1195
parseTableSection(ReadContext & Ctx)1196 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1197 TableSection = Sections.size();
1198 uint32_t Count = readVaruint32(Ctx);
1199 Tables.reserve(Count);
1200 while (Count--) {
1201 wasm::WasmTable T;
1202 T.Type = readTableType(Ctx);
1203 T.Index = NumImportedTables + Tables.size();
1204 Tables.push_back(T);
1205 auto ElemType = Tables.back().Type.ElemType;
1206 if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1207 ElemType != wasm::WASM_TYPE_EXTERNREF) {
1208 return make_error<GenericBinaryError>("invalid table element type",
1209 object_error::parse_failed);
1210 }
1211 }
1212 if (Ctx.Ptr != Ctx.End)
1213 return make_error<GenericBinaryError>("table section ended prematurely",
1214 object_error::parse_failed);
1215 return Error::success();
1216 }
1217
parseMemorySection(ReadContext & Ctx)1218 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1219 uint32_t Count = readVaruint32(Ctx);
1220 Memories.reserve(Count);
1221 while (Count--) {
1222 auto Limits = readLimits(Ctx);
1223 if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1224 HasMemory64 = true;
1225 Memories.push_back(Limits);
1226 }
1227 if (Ctx.Ptr != Ctx.End)
1228 return make_error<GenericBinaryError>("memory section ended prematurely",
1229 object_error::parse_failed);
1230 return Error::success();
1231 }
1232
parseTagSection(ReadContext & Ctx)1233 Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
1234 TagSection = Sections.size();
1235 uint32_t Count = readVaruint32(Ctx);
1236 Tags.reserve(Count);
1237 uint32_t NumTypes = Signatures.size();
1238 while (Count--) {
1239 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1240 return make_error<GenericBinaryError>("invalid attribute",
1241 object_error::parse_failed);
1242 uint32_t Type = readVaruint32(Ctx);
1243 if (Type >= NumTypes)
1244 return make_error<GenericBinaryError>("invalid tag type",
1245 object_error::parse_failed);
1246 wasm::WasmTag Tag;
1247 Tag.Index = NumImportedTags + Tags.size();
1248 Tag.SigIndex = Type;
1249 Tags.push_back(Tag);
1250 }
1251
1252 if (Ctx.Ptr != Ctx.End)
1253 return make_error<GenericBinaryError>("tag section ended prematurely",
1254 object_error::parse_failed);
1255 return Error::success();
1256 }
1257
parseGlobalSection(ReadContext & Ctx)1258 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1259 GlobalSection = Sections.size();
1260 uint32_t Count = readVaruint32(Ctx);
1261 Globals.reserve(Count);
1262 while (Count--) {
1263 wasm::WasmGlobal Global;
1264 Global.Index = NumImportedGlobals + Globals.size();
1265 Global.Type.Type = readUint8(Ctx);
1266 Global.Type.Mutable = readVaruint1(Ctx);
1267 if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1268 return Err;
1269 Globals.push_back(Global);
1270 }
1271 if (Ctx.Ptr != Ctx.End)
1272 return make_error<GenericBinaryError>("global section ended prematurely",
1273 object_error::parse_failed);
1274 return Error::success();
1275 }
1276
parseExportSection(ReadContext & Ctx)1277 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1278 uint32_t Count = readVaruint32(Ctx);
1279 Exports.reserve(Count);
1280 for (uint32_t I = 0; I < Count; I++) {
1281 wasm::WasmExport Ex;
1282 Ex.Name = readString(Ctx);
1283 Ex.Kind = readUint8(Ctx);
1284 Ex.Index = readVaruint32(Ctx);
1285 switch (Ex.Kind) {
1286 case wasm::WASM_EXTERNAL_FUNCTION:
1287
1288 if (!isDefinedFunctionIndex(Ex.Index))
1289 return make_error<GenericBinaryError>("invalid function export",
1290 object_error::parse_failed);
1291 getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1292 break;
1293 case wasm::WASM_EXTERNAL_GLOBAL:
1294 if (!isValidGlobalIndex(Ex.Index))
1295 return make_error<GenericBinaryError>("invalid global export",
1296 object_error::parse_failed);
1297 break;
1298 case wasm::WASM_EXTERNAL_TAG:
1299 if (!isValidTagIndex(Ex.Index))
1300 return make_error<GenericBinaryError>("invalid tag export",
1301 object_error::parse_failed);
1302 break;
1303 case wasm::WASM_EXTERNAL_MEMORY:
1304 case wasm::WASM_EXTERNAL_TABLE:
1305 break;
1306 default:
1307 return make_error<GenericBinaryError>("unexpected export kind",
1308 object_error::parse_failed);
1309 }
1310 Exports.push_back(Ex);
1311 }
1312 if (Ctx.Ptr != Ctx.End)
1313 return make_error<GenericBinaryError>("export section ended prematurely",
1314 object_error::parse_failed);
1315 return Error::success();
1316 }
1317
isValidFunctionIndex(uint32_t Index) const1318 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1319 return Index < NumImportedFunctions + Functions.size();
1320 }
1321
isDefinedFunctionIndex(uint32_t Index) const1322 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1323 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1324 }
1325
isValidGlobalIndex(uint32_t Index) const1326 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1327 return Index < NumImportedGlobals + Globals.size();
1328 }
1329
isValidTableNumber(uint32_t Index) const1330 bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1331 return Index < NumImportedTables + Tables.size();
1332 }
1333
isDefinedGlobalIndex(uint32_t Index) const1334 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1335 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1336 }
1337
isDefinedTableNumber(uint32_t Index) const1338 bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1339 return Index >= NumImportedTables && isValidTableNumber(Index);
1340 }
1341
isValidTagIndex(uint32_t Index) const1342 bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
1343 return Index < NumImportedTags + Tags.size();
1344 }
1345
isDefinedTagIndex(uint32_t Index) const1346 bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
1347 return Index >= NumImportedTags && isValidTagIndex(Index);
1348 }
1349
isValidFunctionSymbol(uint32_t Index) const1350 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1351 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1352 }
1353
isValidTableSymbol(uint32_t Index) const1354 bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1355 return Index < Symbols.size() && Symbols[Index].isTypeTable();
1356 }
1357
isValidGlobalSymbol(uint32_t Index) const1358 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1359 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1360 }
1361
isValidTagSymbol(uint32_t Index) const1362 bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
1363 return Index < Symbols.size() && Symbols[Index].isTypeTag();
1364 }
1365
isValidDataSymbol(uint32_t Index) const1366 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1367 return Index < Symbols.size() && Symbols[Index].isTypeData();
1368 }
1369
isValidSectionSymbol(uint32_t Index) const1370 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1371 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1372 }
1373
getDefinedFunction(uint32_t Index)1374 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1375 assert(isDefinedFunctionIndex(Index));
1376 return Functions[Index - NumImportedFunctions];
1377 }
1378
1379 const wasm::WasmFunction &
getDefinedFunction(uint32_t Index) const1380 WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1381 assert(isDefinedFunctionIndex(Index));
1382 return Functions[Index - NumImportedFunctions];
1383 }
1384
getDefinedGlobal(uint32_t Index)1385 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1386 assert(isDefinedGlobalIndex(Index));
1387 return Globals[Index - NumImportedGlobals];
1388 }
1389
getDefinedTag(uint32_t Index)1390 wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
1391 assert(isDefinedTagIndex(Index));
1392 return Tags[Index - NumImportedTags];
1393 }
1394
parseStartSection(ReadContext & Ctx)1395 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1396 StartFunction = readVaruint32(Ctx);
1397 if (!isValidFunctionIndex(StartFunction))
1398 return make_error<GenericBinaryError>("invalid start function",
1399 object_error::parse_failed);
1400 return Error::success();
1401 }
1402
parseCodeSection(ReadContext & Ctx)1403 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1404 CodeSection = Sections.size();
1405 uint32_t FunctionCount = readVaruint32(Ctx);
1406 if (FunctionCount != Functions.size()) {
1407 return make_error<GenericBinaryError>("invalid function count",
1408 object_error::parse_failed);
1409 }
1410
1411 for (uint32_t i = 0; i < FunctionCount; i++) {
1412 wasm::WasmFunction& Function = Functions[i];
1413 const uint8_t *FunctionStart = Ctx.Ptr;
1414 uint32_t Size = readVaruint32(Ctx);
1415 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1416
1417 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1418 Function.Index = NumImportedFunctions + i;
1419 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1420 Function.Size = FunctionEnd - FunctionStart;
1421
1422 uint32_t NumLocalDecls = readVaruint32(Ctx);
1423 Function.Locals.reserve(NumLocalDecls);
1424 while (NumLocalDecls--) {
1425 wasm::WasmLocalDecl Decl;
1426 Decl.Count = readVaruint32(Ctx);
1427 Decl.Type = readUint8(Ctx);
1428 Function.Locals.push_back(Decl);
1429 }
1430
1431 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1432 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1433 // This will be set later when reading in the linking metadata section.
1434 Function.Comdat = UINT32_MAX;
1435 Ctx.Ptr += BodySize;
1436 assert(Ctx.Ptr == FunctionEnd);
1437 }
1438 if (Ctx.Ptr != Ctx.End)
1439 return make_error<GenericBinaryError>("code section ended prematurely",
1440 object_error::parse_failed);
1441 return Error::success();
1442 }
1443
parseElemSection(ReadContext & Ctx)1444 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1445 uint32_t Count = readVaruint32(Ctx);
1446 ElemSegments.reserve(Count);
1447 while (Count--) {
1448 wasm::WasmElemSegment Segment;
1449 Segment.Flags = readVaruint32(Ctx);
1450
1451 uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1452 wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1453 wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1454 if (Segment.Flags & ~SupportedFlags)
1455 return make_error<GenericBinaryError>(
1456 "Unsupported flags for element segment", object_error::parse_failed);
1457
1458 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
1459 Segment.TableNumber = readVaruint32(Ctx);
1460 else
1461 Segment.TableNumber = 0;
1462 if (!isValidTableNumber(Segment.TableNumber))
1463 return make_error<GenericBinaryError>("invalid TableNumber",
1464 object_error::parse_failed);
1465
1466 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
1467 Segment.Offset.Extended = false;
1468 Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1469 Segment.Offset.Inst.Value.Int32 = 0;
1470 } else {
1471 if (Error Err = readInitExpr(Segment.Offset, Ctx))
1472 return Err;
1473 }
1474
1475 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
1476 Segment.ElemKind = readUint8(Ctx);
1477 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1478 if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
1479 Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
1480 return make_error<GenericBinaryError>("invalid reference type",
1481 object_error::parse_failed);
1482 }
1483 } else {
1484 if (Segment.ElemKind != 0)
1485 return make_error<GenericBinaryError>("invalid elemtype",
1486 object_error::parse_failed);
1487 Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1488 }
1489 } else {
1490 Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1491 }
1492
1493 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
1494 return make_error<GenericBinaryError>(
1495 "elem segment init expressions not yet implemented",
1496 object_error::parse_failed);
1497
1498 uint32_t NumElems = readVaruint32(Ctx);
1499 while (NumElems--) {
1500 Segment.Functions.push_back(readVaruint32(Ctx));
1501 }
1502 ElemSegments.push_back(Segment);
1503 }
1504 if (Ctx.Ptr != Ctx.End)
1505 return make_error<GenericBinaryError>("elem section ended prematurely",
1506 object_error::parse_failed);
1507 return Error::success();
1508 }
1509
parseDataSection(ReadContext & Ctx)1510 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1511 DataSection = Sections.size();
1512 uint32_t Count = readVaruint32(Ctx);
1513 if (DataCount && Count != *DataCount)
1514 return make_error<GenericBinaryError>(
1515 "number of data segments does not match DataCount section");
1516 DataSegments.reserve(Count);
1517 while (Count--) {
1518 WasmSegment Segment;
1519 Segment.Data.InitFlags = readVaruint32(Ctx);
1520 Segment.Data.MemoryIndex =
1521 (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1522 ? readVaruint32(Ctx)
1523 : 0;
1524 if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1525 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1526 return Err;
1527 } else {
1528 Segment.Data.Offset.Extended = false;
1529 Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1530 Segment.Data.Offset.Inst.Value.Int32 = 0;
1531 }
1532 uint32_t Size = readVaruint32(Ctx);
1533 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1534 return make_error<GenericBinaryError>("invalid segment size",
1535 object_error::parse_failed);
1536 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1537 // The rest of these Data fields are set later, when reading in the linking
1538 // metadata section.
1539 Segment.Data.Alignment = 0;
1540 Segment.Data.LinkingFlags = 0;
1541 Segment.Data.Comdat = UINT32_MAX;
1542 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1543 Ctx.Ptr += Size;
1544 DataSegments.push_back(Segment);
1545 }
1546 if (Ctx.Ptr != Ctx.End)
1547 return make_error<GenericBinaryError>("data section ended prematurely",
1548 object_error::parse_failed);
1549 return Error::success();
1550 }
1551
parseDataCountSection(ReadContext & Ctx)1552 Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1553 DataCount = readVaruint32(Ctx);
1554 return Error::success();
1555 }
1556
getHeader() const1557 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1558 return Header;
1559 }
1560
moveSymbolNext(DataRefImpl & Symb) const1561 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1562
getSymbolFlags(DataRefImpl Symb) const1563 Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1564 uint32_t Result = SymbolRef::SF_None;
1565 const WasmSymbol &Sym = getWasmSymbol(Symb);
1566
1567 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1568 if (Sym.isBindingWeak())
1569 Result |= SymbolRef::SF_Weak;
1570 if (!Sym.isBindingLocal())
1571 Result |= SymbolRef::SF_Global;
1572 if (Sym.isHidden())
1573 Result |= SymbolRef::SF_Hidden;
1574 if (!Sym.isDefined())
1575 Result |= SymbolRef::SF_Undefined;
1576 if (Sym.isTypeFunction())
1577 Result |= SymbolRef::SF_Executable;
1578 return Result;
1579 }
1580
symbol_begin() const1581 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1582 DataRefImpl Ref;
1583 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1584 Ref.d.b = 0; // Symbol index
1585 return BasicSymbolRef(Ref, this);
1586 }
1587
symbol_end() const1588 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1589 DataRefImpl Ref;
1590 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1591 Ref.d.b = Symbols.size(); // Symbol index
1592 return BasicSymbolRef(Ref, this);
1593 }
1594
getWasmSymbol(const DataRefImpl & Symb) const1595 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1596 return Symbols[Symb.d.b];
1597 }
1598
getWasmSymbol(const SymbolRef & Symb) const1599 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1600 return getWasmSymbol(Symb.getRawDataRefImpl());
1601 }
1602
getSymbolName(DataRefImpl Symb) const1603 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1604 return getWasmSymbol(Symb).Info.Name;
1605 }
1606
getSymbolAddress(DataRefImpl Symb) const1607 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1608 auto &Sym = getWasmSymbol(Symb);
1609 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1610 isDefinedFunctionIndex(Sym.Info.ElementIndex))
1611 return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
1612 else
1613 return getSymbolValue(Symb);
1614 }
1615
getWasmSymbolValue(const WasmSymbol & Sym) const1616 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1617 switch (Sym.Info.Kind) {
1618 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1619 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1620 case wasm::WASM_SYMBOL_TYPE_TAG:
1621 case wasm::WASM_SYMBOL_TYPE_TABLE:
1622 return Sym.Info.ElementIndex;
1623 case wasm::WASM_SYMBOL_TYPE_DATA: {
1624 // The value of a data symbol is the segment offset, plus the symbol
1625 // offset within the segment.
1626 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1627 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1628 if (Segment.Offset.Extended) {
1629 llvm_unreachable("extended init exprs not supported");
1630 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1631 return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1632 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1633 return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1634 } else {
1635 llvm_unreachable("unknown init expr opcode");
1636 }
1637 }
1638 case wasm::WASM_SYMBOL_TYPE_SECTION:
1639 return 0;
1640 }
1641 llvm_unreachable("invalid symbol type");
1642 }
1643
getSymbolValueImpl(DataRefImpl Symb) const1644 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1645 return getWasmSymbolValue(getWasmSymbol(Symb));
1646 }
1647
getSymbolAlignment(DataRefImpl Symb) const1648 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1649 llvm_unreachable("not yet implemented");
1650 return 0;
1651 }
1652
getCommonSymbolSizeImpl(DataRefImpl Symb) const1653 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1654 llvm_unreachable("not yet implemented");
1655 return 0;
1656 }
1657
1658 Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const1659 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1660 const WasmSymbol &Sym = getWasmSymbol(Symb);
1661
1662 switch (Sym.Info.Kind) {
1663 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1664 return SymbolRef::ST_Function;
1665 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1666 return SymbolRef::ST_Other;
1667 case wasm::WASM_SYMBOL_TYPE_DATA:
1668 return SymbolRef::ST_Data;
1669 case wasm::WASM_SYMBOL_TYPE_SECTION:
1670 return SymbolRef::ST_Debug;
1671 case wasm::WASM_SYMBOL_TYPE_TAG:
1672 return SymbolRef::ST_Other;
1673 case wasm::WASM_SYMBOL_TYPE_TABLE:
1674 return SymbolRef::ST_Other;
1675 }
1676
1677 llvm_unreachable("unknown WasmSymbol::SymbolType");
1678 return SymbolRef::ST_Other;
1679 }
1680
1681 Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const1682 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1683 const WasmSymbol &Sym = getWasmSymbol(Symb);
1684 if (Sym.isUndefined())
1685 return section_end();
1686
1687 DataRefImpl Ref;
1688 Ref.d.a = getSymbolSectionIdImpl(Sym);
1689 return section_iterator(SectionRef(Ref, this));
1690 }
1691
getSymbolSectionId(SymbolRef Symb) const1692 uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1693 const WasmSymbol &Sym = getWasmSymbol(Symb);
1694 return getSymbolSectionIdImpl(Sym);
1695 }
1696
getSymbolSectionIdImpl(const WasmSymbol & Sym) const1697 uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1698 switch (Sym.Info.Kind) {
1699 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1700 return CodeSection;
1701 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1702 return GlobalSection;
1703 case wasm::WASM_SYMBOL_TYPE_DATA:
1704 return DataSection;
1705 case wasm::WASM_SYMBOL_TYPE_SECTION:
1706 return Sym.Info.ElementIndex;
1707 case wasm::WASM_SYMBOL_TYPE_TAG:
1708 return TagSection;
1709 case wasm::WASM_SYMBOL_TYPE_TABLE:
1710 return TableSection;
1711 default:
1712 llvm_unreachable("unknown WasmSymbol::SymbolType");
1713 }
1714 }
1715
moveSectionNext(DataRefImpl & Sec) const1716 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1717
getSectionName(DataRefImpl Sec) const1718 Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1719 const WasmSection &S = Sections[Sec.d.a];
1720 if (S.Type == wasm::WASM_SEC_CUSTOM)
1721 return S.Name;
1722 if (S.Type > wasm::WASM_SEC_LAST_KNOWN)
1723 return createStringError(object_error::invalid_section_index, "");
1724 return wasm::sectionTypeToString(S.Type);
1725 }
1726
getSectionAddress(DataRefImpl Sec) const1727 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1728
getSectionIndex(DataRefImpl Sec) const1729 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1730 return Sec.d.a;
1731 }
1732
getSectionSize(DataRefImpl Sec) const1733 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1734 const WasmSection &S = Sections[Sec.d.a];
1735 return S.Content.size();
1736 }
1737
1738 Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const1739 WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1740 const WasmSection &S = Sections[Sec.d.a];
1741 // This will never fail since wasm sections can never be empty (user-sections
1742 // must have a name and non-user sections each have a defined structure).
1743 return S.Content;
1744 }
1745
getSectionAlignment(DataRefImpl Sec) const1746 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1747 return 1;
1748 }
1749
isSectionCompressed(DataRefImpl Sec) const1750 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1751 return false;
1752 }
1753
isSectionText(DataRefImpl Sec) const1754 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1755 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1756 }
1757
isSectionData(DataRefImpl Sec) const1758 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1759 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1760 }
1761
isSectionBSS(DataRefImpl Sec) const1762 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1763
isSectionVirtual(DataRefImpl Sec) const1764 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1765
section_rel_begin(DataRefImpl Ref) const1766 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1767 DataRefImpl RelocRef;
1768 RelocRef.d.a = Ref.d.a;
1769 RelocRef.d.b = 0;
1770 return relocation_iterator(RelocationRef(RelocRef, this));
1771 }
1772
section_rel_end(DataRefImpl Ref) const1773 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1774 const WasmSection &Sec = getWasmSection(Ref);
1775 DataRefImpl RelocRef;
1776 RelocRef.d.a = Ref.d.a;
1777 RelocRef.d.b = Sec.Relocations.size();
1778 return relocation_iterator(RelocationRef(RelocRef, this));
1779 }
1780
moveRelocationNext(DataRefImpl & Rel) const1781 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1782
getRelocationOffset(DataRefImpl Ref) const1783 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1784 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1785 return Rel.Offset;
1786 }
1787
getRelocationSymbol(DataRefImpl Ref) const1788 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1789 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1790 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
1791 return symbol_end();
1792 DataRefImpl Sym;
1793 Sym.d.a = 1;
1794 Sym.d.b = Rel.Index;
1795 return symbol_iterator(SymbolRef(Sym, this));
1796 }
1797
getRelocationType(DataRefImpl Ref) const1798 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1799 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1800 return Rel.Type;
1801 }
1802
getRelocationTypeName(DataRefImpl Ref,SmallVectorImpl<char> & Result) const1803 void WasmObjectFile::getRelocationTypeName(
1804 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1805 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1806 StringRef Res = "Unknown";
1807
1808 #define WASM_RELOC(name, value) \
1809 case wasm::name: \
1810 Res = #name; \
1811 break;
1812
1813 switch (Rel.Type) {
1814 #include "llvm/BinaryFormat/WasmRelocs.def"
1815 }
1816
1817 #undef WASM_RELOC
1818
1819 Result.append(Res.begin(), Res.end());
1820 }
1821
section_begin() const1822 section_iterator WasmObjectFile::section_begin() const {
1823 DataRefImpl Ref;
1824 Ref.d.a = 0;
1825 return section_iterator(SectionRef(Ref, this));
1826 }
1827
section_end() const1828 section_iterator WasmObjectFile::section_end() const {
1829 DataRefImpl Ref;
1830 Ref.d.a = Sections.size();
1831 return section_iterator(SectionRef(Ref, this));
1832 }
1833
getBytesInAddress() const1834 uint8_t WasmObjectFile::getBytesInAddress() const {
1835 return HasMemory64 ? 8 : 4;
1836 }
1837
getFileFormatName() const1838 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1839
getArch() const1840 Triple::ArchType WasmObjectFile::getArch() const {
1841 return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
1842 }
1843
getFeatures() const1844 SubtargetFeatures WasmObjectFile::getFeatures() const {
1845 return SubtargetFeatures();
1846 }
1847
isRelocatableObject() const1848 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1849
isSharedObject() const1850 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1851
getWasmSection(DataRefImpl Ref) const1852 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1853 assert(Ref.d.a < Sections.size());
1854 return Sections[Ref.d.a];
1855 }
1856
1857 const WasmSection &
getWasmSection(const SectionRef & Section) const1858 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1859 return getWasmSection(Section.getRawDataRefImpl());
1860 }
1861
1862 const wasm::WasmRelocation &
getWasmRelocation(const RelocationRef & Ref) const1863 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1864 return getWasmRelocation(Ref.getRawDataRefImpl());
1865 }
1866
1867 const wasm::WasmRelocation &
getWasmRelocation(DataRefImpl Ref) const1868 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1869 assert(Ref.d.a < Sections.size());
1870 const WasmSection &Sec = Sections[Ref.d.a];
1871 assert(Ref.d.b < Sec.Relocations.size());
1872 return Sec.Relocations[Ref.d.b];
1873 }
1874
getSectionOrder(unsigned ID,StringRef CustomSectionName)1875 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1876 StringRef CustomSectionName) {
1877 switch (ID) {
1878 case wasm::WASM_SEC_CUSTOM:
1879 return StringSwitch<unsigned>(CustomSectionName)
1880 .Case("dylink", WASM_SEC_ORDER_DYLINK)
1881 .Case("dylink.0", WASM_SEC_ORDER_DYLINK)
1882 .Case("linking", WASM_SEC_ORDER_LINKING)
1883 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1884 .Case("name", WASM_SEC_ORDER_NAME)
1885 .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1886 .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
1887 .Default(WASM_SEC_ORDER_NONE);
1888 case wasm::WASM_SEC_TYPE:
1889 return WASM_SEC_ORDER_TYPE;
1890 case wasm::WASM_SEC_IMPORT:
1891 return WASM_SEC_ORDER_IMPORT;
1892 case wasm::WASM_SEC_FUNCTION:
1893 return WASM_SEC_ORDER_FUNCTION;
1894 case wasm::WASM_SEC_TABLE:
1895 return WASM_SEC_ORDER_TABLE;
1896 case wasm::WASM_SEC_MEMORY:
1897 return WASM_SEC_ORDER_MEMORY;
1898 case wasm::WASM_SEC_GLOBAL:
1899 return WASM_SEC_ORDER_GLOBAL;
1900 case wasm::WASM_SEC_EXPORT:
1901 return WASM_SEC_ORDER_EXPORT;
1902 case wasm::WASM_SEC_START:
1903 return WASM_SEC_ORDER_START;
1904 case wasm::WASM_SEC_ELEM:
1905 return WASM_SEC_ORDER_ELEM;
1906 case wasm::WASM_SEC_CODE:
1907 return WASM_SEC_ORDER_CODE;
1908 case wasm::WASM_SEC_DATA:
1909 return WASM_SEC_ORDER_DATA;
1910 case wasm::WASM_SEC_DATACOUNT:
1911 return WASM_SEC_ORDER_DATACOUNT;
1912 case wasm::WASM_SEC_TAG:
1913 return WASM_SEC_ORDER_TAG;
1914 default:
1915 return WASM_SEC_ORDER_NONE;
1916 }
1917 }
1918
1919 // Represents the edges in a directed graph where any node B reachable from node
1920 // A is not allowed to appear before A in the section ordering, but may appear
1921 // afterward.
1922 int WasmSectionOrderChecker::DisallowedPredecessors
1923 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
1924 // WASM_SEC_ORDER_NONE
1925 {},
1926 // WASM_SEC_ORDER_TYPE
1927 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
1928 // WASM_SEC_ORDER_IMPORT
1929 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
1930 // WASM_SEC_ORDER_FUNCTION
1931 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
1932 // WASM_SEC_ORDER_TABLE
1933 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
1934 // WASM_SEC_ORDER_MEMORY
1935 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
1936 // WASM_SEC_ORDER_TAG
1937 {WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
1938 // WASM_SEC_ORDER_GLOBAL
1939 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
1940 // WASM_SEC_ORDER_EXPORT
1941 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
1942 // WASM_SEC_ORDER_START
1943 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
1944 // WASM_SEC_ORDER_ELEM
1945 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
1946 // WASM_SEC_ORDER_DATACOUNT
1947 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
1948 // WASM_SEC_ORDER_CODE
1949 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
1950 // WASM_SEC_ORDER_DATA
1951 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
1952
1953 // Custom Sections
1954 // WASM_SEC_ORDER_DYLINK
1955 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
1956 // WASM_SEC_ORDER_LINKING
1957 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
1958 // WASM_SEC_ORDER_RELOC (can be repeated)
1959 {},
1960 // WASM_SEC_ORDER_NAME
1961 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
1962 // WASM_SEC_ORDER_PRODUCERS
1963 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
1964 // WASM_SEC_ORDER_TARGET_FEATURES
1965 {WASM_SEC_ORDER_TARGET_FEATURES}};
1966
isValidSectionOrder(unsigned ID,StringRef CustomSectionName)1967 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1968 StringRef CustomSectionName) {
1969 int Order = getSectionOrder(ID, CustomSectionName);
1970 if (Order == WASM_SEC_ORDER_NONE)
1971 return true;
1972
1973 // Disallowed predecessors we need to check for
1974 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
1975
1976 // Keep track of completed checks to avoid repeating work
1977 bool Checked[WASM_NUM_SEC_ORDERS] = {};
1978
1979 int Curr = Order;
1980 while (true) {
1981 // Add new disallowed predecessors to work list
1982 for (size_t I = 0;; ++I) {
1983 int Next = DisallowedPredecessors[Curr][I];
1984 if (Next == WASM_SEC_ORDER_NONE)
1985 break;
1986 if (Checked[Next])
1987 continue;
1988 WorkList.push_back(Next);
1989 Checked[Next] = true;
1990 }
1991
1992 if (WorkList.empty())
1993 break;
1994
1995 // Consider next disallowed predecessor
1996 Curr = WorkList.pop_back_val();
1997 if (Seen[Curr])
1998 return false;
1999 }
2000
2001 // Have not seen any disallowed predecessors
2002 Seen[Order] = true;
2003 return true;
2004 }
2005