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