1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements Wasm object file writer information. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallPtrSet.h" 16 #include "llvm/BinaryFormat/Wasm.h" 17 #include "llvm/MC/MCAsmBackend.h" 18 #include "llvm/MC/MCAsmLayout.h" 19 #include "llvm/MC/MCAssembler.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCExpr.h" 22 #include "llvm/MC/MCFixupKindInfo.h" 23 #include "llvm/MC/MCObjectWriter.h" 24 #include "llvm/MC/MCSectionWasm.h" 25 #include "llvm/MC/MCSymbolWasm.h" 26 #include "llvm/MC/MCValue.h" 27 #include "llvm/MC/MCWasmObjectWriter.h" 28 #include "llvm/Support/Casting.h" 29 #include "llvm/Support/Debug.h" 30 #include "llvm/Support/ErrorHandling.h" 31 #include "llvm/Support/LEB128.h" 32 #include "llvm/Support/StringSaver.h" 33 #include <vector> 34 35 using namespace llvm; 36 37 #define DEBUG_TYPE "mc" 38 39 namespace { 40 41 // Went we ceate the indirect function table we start at 1, so that there is 42 // and emtpy slot at 0 and therefore calling a null function pointer will trap. 43 static const uint32_t kInitialTableOffset = 1; 44 45 // For patching purposes, we need to remember where each section starts, both 46 // for patching up the section size field, and for patching up references to 47 // locations within the section. 48 struct SectionBookkeeping { 49 // Where the size of the section is written. 50 uint64_t SizeOffset; 51 // Where the contents of the section starts (after the header). 52 uint64_t ContentsOffset; 53 }; 54 55 // The signature of a wasm function, in a struct capable of being used as a 56 // DenseMap key. 57 struct WasmFunctionType { 58 // Support empty and tombstone instances, needed by DenseMap. 59 enum { Plain, Empty, Tombstone } State; 60 61 // The return types of the function. 62 SmallVector<wasm::ValType, 1> Returns; 63 64 // The parameter types of the function. 65 SmallVector<wasm::ValType, 4> Params; 66 67 WasmFunctionType() : State(Plain) {} 68 69 bool operator==(const WasmFunctionType &Other) const { 70 return State == Other.State && Returns == Other.Returns && 71 Params == Other.Params; 72 } 73 }; 74 75 // Traits for using WasmFunctionType in a DenseMap. 76 struct WasmFunctionTypeDenseMapInfo { 77 static WasmFunctionType getEmptyKey() { 78 WasmFunctionType FuncTy; 79 FuncTy.State = WasmFunctionType::Empty; 80 return FuncTy; 81 } 82 static WasmFunctionType getTombstoneKey() { 83 WasmFunctionType FuncTy; 84 FuncTy.State = WasmFunctionType::Tombstone; 85 return FuncTy; 86 } 87 static unsigned getHashValue(const WasmFunctionType &FuncTy) { 88 uintptr_t Value = FuncTy.State; 89 for (wasm::ValType Ret : FuncTy.Returns) 90 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret)); 91 for (wasm::ValType Param : FuncTy.Params) 92 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param)); 93 return Value; 94 } 95 static bool isEqual(const WasmFunctionType &LHS, 96 const WasmFunctionType &RHS) { 97 return LHS == RHS; 98 } 99 }; 100 101 // A wasm data segment. A wasm binary contains only a single data section 102 // but that can contain many segments, each with their own virtual location 103 // in memory. Each MCSection data created by llvm is modeled as its own 104 // wasm data segment. 105 struct WasmDataSegment { 106 MCSectionWasm *Section; 107 StringRef Name; 108 uint32_t Offset; 109 uint32_t Alignment; 110 uint32_t Flags; 111 SmallVector<char, 4> Data; 112 }; 113 114 // A wasm function to be written into the function section. 115 struct WasmFunction { 116 int32_t Type; 117 const MCSymbolWasm *Sym; 118 }; 119 120 // A wasm global to be written into the global section. 121 struct WasmGlobal { 122 wasm::WasmGlobalType Type; 123 uint64_t InitialValue; 124 }; 125 126 // Information about a single item which is part of a COMDAT. For each data 127 // segment or function which is in the COMDAT, there is a corresponding 128 // WasmComdatEntry. 129 struct WasmComdatEntry { 130 unsigned Kind; 131 uint32_t Index; 132 }; 133 134 // Information about a single relocation. 135 struct WasmRelocationEntry { 136 uint64_t Offset; // Where is the relocation. 137 const MCSymbolWasm *Symbol; // The symbol to relocate with. 138 int64_t Addend; // A value to add to the symbol. 139 unsigned Type; // The type of the relocation. 140 const MCSectionWasm *FixupSection;// The section the relocation is targeting. 141 142 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, 143 int64_t Addend, unsigned Type, 144 const MCSectionWasm *FixupSection) 145 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), 146 FixupSection(FixupSection) {} 147 148 bool hasAddend() const { 149 switch (Type) { 150 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: 151 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 152 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: 153 return true; 154 default: 155 return false; 156 } 157 } 158 159 void print(raw_ostream &Out) const { 160 Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend 161 << ", Type=" << Type 162 << ", FixupSection=" << FixupSection->getSectionName(); 163 } 164 165 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 166 LLVM_DUMP_METHOD void dump() const { print(dbgs()); } 167 #endif 168 }; 169 170 #if !defined(NDEBUG) 171 raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { 172 Rel.print(OS); 173 return OS; 174 } 175 #endif 176 177 class WasmObjectWriter : public MCObjectWriter { 178 /// The target specific Wasm writer instance. 179 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter; 180 181 // Relocations for fixing up references in the code section. 182 std::vector<WasmRelocationEntry> CodeRelocations; 183 184 // Relocations for fixing up references in the data section. 185 std::vector<WasmRelocationEntry> DataRelocations; 186 187 // Index values to use for fixing up call_indirect type indices. 188 // Maps function symbols to the index of the type of the function 189 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices; 190 // Maps function symbols to the table element index space. Used 191 // for TABLE_INDEX relocation types (i.e. address taken functions). 192 DenseMap<const MCSymbolWasm *, uint32_t> TableIndices; 193 // Maps function/global symbols to the (shared) Symbol index space. 194 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices; 195 // Maps function/global symbols to the function/global Wasm index space. 196 DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; 197 // Maps data symbols to the Wasm segment and offset/size with the segment. 198 DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; 199 200 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> 201 FunctionTypeIndices; 202 SmallVector<WasmFunctionType, 4> FunctionTypes; 203 SmallVector<WasmGlobal, 4> Globals; 204 SmallVector<WasmDataSegment, 4> DataSegments; 205 unsigned NumFunctionImports = 0; 206 unsigned NumGlobalImports = 0; 207 208 // TargetObjectWriter wrappers. 209 bool is64Bit() const { return TargetObjectWriter->is64Bit(); } 210 unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const { 211 return TargetObjectWriter->getRelocType(Target, Fixup); 212 } 213 214 void startSection(SectionBookkeeping &Section, unsigned SectionId, 215 const char *Name = nullptr); 216 void endSection(SectionBookkeeping &Section); 217 218 public: 219 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, 220 raw_pwrite_stream &OS) 221 : MCObjectWriter(OS, /*IsLittleEndian=*/true), 222 TargetObjectWriter(std::move(MOTW)) {} 223 224 ~WasmObjectWriter() override; 225 226 private: 227 void reset() override { 228 CodeRelocations.clear(); 229 DataRelocations.clear(); 230 TypeIndices.clear(); 231 SymbolIndices.clear(); 232 WasmIndices.clear(); 233 TableIndices.clear(); 234 DataLocations.clear(); 235 FunctionTypeIndices.clear(); 236 FunctionTypes.clear(); 237 Globals.clear(); 238 DataSegments.clear(); 239 MCObjectWriter::reset(); 240 NumFunctionImports = 0; 241 NumGlobalImports = 0; 242 } 243 244 void writeHeader(const MCAssembler &Asm); 245 246 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 247 const MCFragment *Fragment, const MCFixup &Fixup, 248 MCValue Target, uint64_t &FixedValue) override; 249 250 void executePostLayoutBinding(MCAssembler &Asm, 251 const MCAsmLayout &Layout) override; 252 253 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; 254 255 void writeString(const StringRef Str) { 256 encodeULEB128(Str.size(), getStream()); 257 writeBytes(Str); 258 } 259 260 void writeValueType(wasm::ValType Ty) { 261 write8(static_cast<uint8_t>(Ty)); 262 } 263 264 void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes); 265 void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, 266 uint32_t NumElements); 267 void writeFunctionSection(ArrayRef<WasmFunction> Functions); 268 void writeGlobalSection(); 269 void writeExportSection(ArrayRef<wasm::WasmExport> Exports); 270 void writeElemSection(ArrayRef<uint32_t> TableElems); 271 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, 272 ArrayRef<WasmFunction> Functions); 273 void writeDataSection(); 274 void writeCodeRelocSection(); 275 void writeDataRelocSection(); 276 void writeLinkingMetaDataSection( 277 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, 278 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, 279 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats); 280 281 uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); 282 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, 283 uint64_t ContentsOffset); 284 285 void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations); 286 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); 287 uint32_t getFunctionType(const MCSymbolWasm& Symbol); 288 uint32_t registerFunctionType(const MCSymbolWasm& Symbol); 289 }; 290 291 } // end anonymous namespace 292 293 WasmObjectWriter::~WasmObjectWriter() {} 294 295 // Write out a section header and a patchable section size field. 296 void WasmObjectWriter::startSection(SectionBookkeeping &Section, 297 unsigned SectionId, 298 const char *Name) { 299 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && 300 "Only custom sections can have names"); 301 302 DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); 303 write8(SectionId); 304 305 Section.SizeOffset = getStream().tell(); 306 307 // The section size. We don't know the size yet, so reserve enough space 308 // for any 32-bit value; we'll patch it later. 309 encodeULEB128(UINT32_MAX, getStream()); 310 311 // The position where the section starts, for measuring its size. 312 Section.ContentsOffset = getStream().tell(); 313 314 // Custom sections in wasm also have a string identifier. 315 if (SectionId == wasm::WASM_SEC_CUSTOM) { 316 assert(Name); 317 writeString(StringRef(Name)); 318 } 319 } 320 321 // Now that the section is complete and we know how big it is, patch up the 322 // section size field at the start of the section. 323 void WasmObjectWriter::endSection(SectionBookkeeping &Section) { 324 uint64_t Size = getStream().tell() - Section.ContentsOffset; 325 if (uint32_t(Size) != Size) 326 report_fatal_error("section size does not fit in a uint32_t"); 327 328 DEBUG(dbgs() << "endSection size=" << Size << "\n"); 329 330 // Write the final section size to the payload_len field, which follows 331 // the section id byte. 332 uint8_t Buffer[16]; 333 unsigned SizeLen = encodeULEB128(Size, Buffer, 5); 334 assert(SizeLen == 5); 335 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); 336 } 337 338 // Emit the Wasm header. 339 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { 340 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic))); 341 writeLE32(wasm::WasmVersion); 342 } 343 344 void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, 345 const MCAsmLayout &Layout) { 346 } 347 348 void WasmObjectWriter::recordRelocation(MCAssembler &Asm, 349 const MCAsmLayout &Layout, 350 const MCFragment *Fragment, 351 const MCFixup &Fixup, MCValue Target, 352 uint64_t &FixedValue) { 353 MCAsmBackend &Backend = Asm.getBackend(); 354 bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & 355 MCFixupKindInfo::FKF_IsPCRel; 356 const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent()); 357 uint64_t C = Target.getConstant(); 358 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 359 MCContext &Ctx = Asm.getContext(); 360 361 // The .init_array isn't translated as data, so don't do relocations in it. 362 if (FixupSection.getSectionName().startswith(".init_array")) 363 return; 364 365 // TODO(sbc): Add support for debug sections. 366 if (FixupSection.getKind().isMetadata()) 367 return; 368 369 if (const MCSymbolRefExpr *RefB = Target.getSymB()) { 370 assert(RefB->getKind() == MCSymbolRefExpr::VK_None && 371 "Should not have constructed this"); 372 373 // Let A, B and C being the components of Target and R be the location of 374 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). 375 // If it is pcrel, we want to compute (A - B + C - R). 376 377 // In general, Wasm has no relocations for -B. It can only represent (A + C) 378 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can 379 // replace B to implement it: (A - R - K + C) 380 if (IsPCRel) { 381 Ctx.reportError( 382 Fixup.getLoc(), 383 "No relocation available to represent this relative expression"); 384 return; 385 } 386 387 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol()); 388 389 if (SymB.isUndefined()) { 390 Ctx.reportError(Fixup.getLoc(), 391 Twine("symbol '") + SymB.getName() + 392 "' can not be undefined in a subtraction expression"); 393 return; 394 } 395 396 assert(!SymB.isAbsolute() && "Should have been folded"); 397 const MCSection &SecB = SymB.getSection(); 398 if (&SecB != &FixupSection) { 399 Ctx.reportError(Fixup.getLoc(), 400 "Cannot represent a difference across sections"); 401 return; 402 } 403 404 uint64_t SymBOffset = Layout.getSymbolOffset(SymB); 405 uint64_t K = SymBOffset - FixupOffset; 406 IsPCRel = true; 407 C -= K; 408 } 409 410 // We either rejected the fixup or folded B into C at this point. 411 const MCSymbolRefExpr *RefA = Target.getSymA(); 412 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr; 413 414 if (SymA && SymA->isVariable()) { 415 const MCExpr *Expr = SymA->getVariableValue(); 416 const auto *Inner = cast<MCSymbolRefExpr>(Expr); 417 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) 418 llvm_unreachable("weakref used in reloc not yet implemented"); 419 } 420 421 // Put any constant offset in an addend. Offsets can be negative, and 422 // LLVM expects wrapping, in contrast to wasm's immediates which can't 423 // be negative and don't wrap. 424 FixedValue = 0; 425 426 if (SymA) 427 SymA->setUsedInReloc(); 428 429 assert(!IsPCRel); 430 assert(SymA); 431 432 unsigned Type = getRelocType(Target, Fixup); 433 434 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); 435 DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); 436 437 // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required 438 // to be against a named symbol. 439 // TODO(sbc): Add support for relocations against unnamed temporaries such 440 // as those generated by llvm's `blockaddress`. 441 // See: test/MC/WebAssembly/blockaddress.ll 442 if (SymA->getName().empty() && Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) 443 report_fatal_error("relocations against un-named temporaries are not yet " 444 "supported by wasm"); 445 446 if (FixupSection.isWasmData()) 447 DataRelocations.push_back(Rec); 448 else if (FixupSection.getKind().isText()) 449 CodeRelocations.push_back(Rec); 450 else 451 llvm_unreachable("unexpected section type"); 452 } 453 454 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded 455 // to allow patching. 456 static void 457 WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 458 uint8_t Buffer[5]; 459 unsigned SizeLen = encodeULEB128(X, Buffer, 5); 460 assert(SizeLen == 5); 461 Stream.pwrite((char *)Buffer, SizeLen, Offset); 462 } 463 464 // Write X as an signed LEB value at offset Offset in Stream, padded 465 // to allow patching. 466 static void 467 WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { 468 uint8_t Buffer[5]; 469 unsigned SizeLen = encodeSLEB128(X, Buffer, 5); 470 assert(SizeLen == 5); 471 Stream.pwrite((char *)Buffer, SizeLen, Offset); 472 } 473 474 // Write X as a plain integer value at offset Offset in Stream. 475 static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 476 uint8_t Buffer[4]; 477 support::endian::write32le(Buffer, X); 478 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); 479 } 480 481 static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) { 482 if (Symbol.isVariable()) { 483 const MCExpr *Expr = Symbol.getVariableValue(); 484 auto *Inner = cast<MCSymbolRefExpr>(Expr); 485 return cast<MCSymbolWasm>(&Inner->getSymbol()); 486 } 487 return &Symbol; 488 } 489 490 // Compute a value to write into the code at the location covered 491 // by RelEntry. This value isn't used by the static linker; it just serves 492 // to make the object format more readable and more likely to be directly 493 // useable. 494 uint32_t 495 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { 496 switch (RelEntry.Type) { 497 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 498 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { 499 // Provisional value is table address of the resolved symbol itself 500 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); 501 assert(Sym->isFunction()); 502 return TableIndices[Sym]; 503 } 504 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: 505 // Provisional value is same as the index 506 return getRelocationIndexValue(RelEntry); 507 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 508 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: 509 // Provisional value is function/global Wasm index 510 if (!WasmIndices.count(RelEntry.Symbol)) 511 report_fatal_error("symbol not found in wasm index space: " + 512 RelEntry.Symbol->getName()); 513 return WasmIndices[RelEntry.Symbol]; 514 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: 515 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: 516 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { 517 // Provisional value is address of the global 518 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); 519 // For undefined symbols, use zero 520 if (!Sym->isDefined()) 521 return 0; 522 const wasm::WasmDataReference &Ref = DataLocations[Sym]; 523 const WasmDataSegment &Segment = DataSegments[Ref.Segment]; 524 // Ignore overflow. LLVM allows address arithmetic to silently wrap. 525 return Segment.Offset + Ref.Offset + RelEntry.Addend; 526 } 527 default: 528 llvm_unreachable("invalid relocation type"); 529 } 530 } 531 532 static void addData(SmallVectorImpl<char> &DataBytes, 533 MCSectionWasm &DataSection) { 534 DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); 535 536 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); 537 538 for (const MCFragment &Frag : DataSection) { 539 if (Frag.hasInstructions()) 540 report_fatal_error("only data supported in data sections"); 541 542 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) { 543 if (Align->getValueSize() != 1) 544 report_fatal_error("only byte values supported for alignment"); 545 // If nops are requested, use zeros, as this is the data section. 546 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); 547 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(), 548 Align->getAlignment()), 549 DataBytes.size() + 550 Align->getMaxBytesToEmit()); 551 DataBytes.resize(Size, Value); 552 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { 553 int64_t Size; 554 if (!Fill->getSize().evaluateAsAbsolute(Size)) 555 llvm_unreachable("The fill should be an assembler constant"); 556 DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); 557 } else { 558 const auto &DataFrag = cast<MCDataFragment>(Frag); 559 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 560 561 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); 562 } 563 } 564 565 DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); 566 } 567 568 uint32_t 569 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) { 570 if (RelEntry.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) { 571 if (!TypeIndices.count(RelEntry.Symbol)) 572 report_fatal_error("symbol not found in type index space: " + 573 RelEntry.Symbol->getName()); 574 return TypeIndices[RelEntry.Symbol]; 575 } 576 577 if (!SymbolIndices.count(RelEntry.Symbol)) 578 report_fatal_error("symbol not found in symbol index space: " + 579 RelEntry.Symbol->getName()); 580 return SymbolIndices[RelEntry.Symbol]; 581 } 582 583 // Apply the portions of the relocation records that we can handle ourselves 584 // directly. 585 void WasmObjectWriter::applyRelocations( 586 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) { 587 raw_pwrite_stream &Stream = getStream(); 588 for (const WasmRelocationEntry &RelEntry : Relocations) { 589 uint64_t Offset = ContentsOffset + 590 RelEntry.FixupSection->getSectionOffset() + 591 RelEntry.Offset; 592 593 DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); 594 uint32_t Value = getProvisionalValue(RelEntry); 595 596 switch (RelEntry.Type) { 597 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 598 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: 599 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: 600 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: 601 WritePatchableLEB(Stream, Value, Offset); 602 break; 603 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: 604 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: 605 WriteI32(Stream, Value, Offset); 606 break; 607 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 608 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: 609 WritePatchableSLEB(Stream, Value, Offset); 610 break; 611 default: 612 llvm_unreachable("invalid relocation type"); 613 } 614 } 615 } 616 617 // Write out the portions of the relocation records that the linker will 618 // need to handle. 619 void WasmObjectWriter::writeRelocations( 620 ArrayRef<WasmRelocationEntry> Relocations) { 621 raw_pwrite_stream &Stream = getStream(); 622 for (const WasmRelocationEntry& RelEntry : Relocations) { 623 624 uint64_t Offset = RelEntry.Offset + 625 RelEntry.FixupSection->getSectionOffset(); 626 uint32_t Index = getRelocationIndexValue(RelEntry); 627 628 write8(RelEntry.Type); 629 encodeULEB128(Offset, Stream); 630 encodeULEB128(Index, Stream); 631 if (RelEntry.hasAddend()) 632 encodeSLEB128(RelEntry.Addend, Stream); 633 } 634 } 635 636 void WasmObjectWriter::writeTypeSection( 637 ArrayRef<WasmFunctionType> FunctionTypes) { 638 if (FunctionTypes.empty()) 639 return; 640 641 SectionBookkeeping Section; 642 startSection(Section, wasm::WASM_SEC_TYPE); 643 644 encodeULEB128(FunctionTypes.size(), getStream()); 645 646 for (const WasmFunctionType &FuncTy : FunctionTypes) { 647 write8(wasm::WASM_TYPE_FUNC); 648 encodeULEB128(FuncTy.Params.size(), getStream()); 649 for (wasm::ValType Ty : FuncTy.Params) 650 writeValueType(Ty); 651 encodeULEB128(FuncTy.Returns.size(), getStream()); 652 for (wasm::ValType Ty : FuncTy.Returns) 653 writeValueType(Ty); 654 } 655 656 endSection(Section); 657 } 658 659 void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports, 660 uint32_t DataSize, 661 uint32_t NumElements) { 662 if (Imports.empty()) 663 return; 664 665 uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; 666 667 SectionBookkeeping Section; 668 startSection(Section, wasm::WASM_SEC_IMPORT); 669 670 encodeULEB128(Imports.size(), getStream()); 671 for (const wasm::WasmImport &Import : Imports) { 672 writeString(Import.Module); 673 writeString(Import.Field); 674 write8(Import.Kind); 675 676 switch (Import.Kind) { 677 case wasm::WASM_EXTERNAL_FUNCTION: 678 encodeULEB128(Import.SigIndex, getStream()); 679 break; 680 case wasm::WASM_EXTERNAL_GLOBAL: 681 write8(Import.Global.Type); 682 write8(Import.Global.Mutable ? 1 : 0); 683 break; 684 case wasm::WASM_EXTERNAL_MEMORY: 685 encodeULEB128(0, getStream()); // flags 686 encodeULEB128(NumPages, getStream()); // initial 687 break; 688 case wasm::WASM_EXTERNAL_TABLE: 689 write8(Import.Table.ElemType); 690 encodeULEB128(0, getStream()); // flags 691 encodeULEB128(NumElements, getStream()); // initial 692 break; 693 default: 694 llvm_unreachable("unsupported import kind"); 695 } 696 } 697 698 endSection(Section); 699 } 700 701 void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { 702 if (Functions.empty()) 703 return; 704 705 SectionBookkeeping Section; 706 startSection(Section, wasm::WASM_SEC_FUNCTION); 707 708 encodeULEB128(Functions.size(), getStream()); 709 for (const WasmFunction &Func : Functions) 710 encodeULEB128(Func.Type, getStream()); 711 712 endSection(Section); 713 } 714 715 void WasmObjectWriter::writeGlobalSection() { 716 if (Globals.empty()) 717 return; 718 719 SectionBookkeeping Section; 720 startSection(Section, wasm::WASM_SEC_GLOBAL); 721 722 encodeULEB128(Globals.size(), getStream()); 723 for (const WasmGlobal &Global : Globals) { 724 writeValueType(static_cast<wasm::ValType>(Global.Type.Type)); 725 write8(Global.Type.Mutable); 726 727 write8(wasm::WASM_OPCODE_I32_CONST); 728 encodeSLEB128(Global.InitialValue, getStream()); 729 write8(wasm::WASM_OPCODE_END); 730 } 731 732 endSection(Section); 733 } 734 735 void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) { 736 if (Exports.empty()) 737 return; 738 739 SectionBookkeeping Section; 740 startSection(Section, wasm::WASM_SEC_EXPORT); 741 742 encodeULEB128(Exports.size(), getStream()); 743 for (const wasm::WasmExport &Export : Exports) { 744 writeString(Export.Name); 745 write8(Export.Kind); 746 encodeULEB128(Export.Index, getStream()); 747 } 748 749 endSection(Section); 750 } 751 752 void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { 753 if (TableElems.empty()) 754 return; 755 756 SectionBookkeeping Section; 757 startSection(Section, wasm::WASM_SEC_ELEM); 758 759 encodeULEB128(1, getStream()); // number of "segments" 760 encodeULEB128(0, getStream()); // the table index 761 762 // init expr for starting offset 763 write8(wasm::WASM_OPCODE_I32_CONST); 764 encodeSLEB128(kInitialTableOffset, getStream()); 765 write8(wasm::WASM_OPCODE_END); 766 767 encodeULEB128(TableElems.size(), getStream()); 768 for (uint32_t Elem : TableElems) 769 encodeULEB128(Elem, getStream()); 770 771 endSection(Section); 772 } 773 774 void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, 775 const MCAsmLayout &Layout, 776 ArrayRef<WasmFunction> Functions) { 777 if (Functions.empty()) 778 return; 779 780 SectionBookkeeping Section; 781 startSection(Section, wasm::WASM_SEC_CODE); 782 783 encodeULEB128(Functions.size(), getStream()); 784 785 for (const WasmFunction &Func : Functions) { 786 auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection()); 787 788 int64_t Size = 0; 789 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) 790 report_fatal_error(".size expression must be evaluatable"); 791 792 encodeULEB128(Size, getStream()); 793 FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); 794 Asm.writeSectionData(&FuncSection, Layout); 795 } 796 797 // Apply fixups. 798 applyRelocations(CodeRelocations, Section.ContentsOffset); 799 800 endSection(Section); 801 } 802 803 void WasmObjectWriter::writeDataSection() { 804 if (DataSegments.empty()) 805 return; 806 807 SectionBookkeeping Section; 808 startSection(Section, wasm::WASM_SEC_DATA); 809 810 encodeULEB128(DataSegments.size(), getStream()); // count 811 812 for (const WasmDataSegment &Segment : DataSegments) { 813 encodeULEB128(0, getStream()); // memory index 814 write8(wasm::WASM_OPCODE_I32_CONST); 815 encodeSLEB128(Segment.Offset, getStream()); // offset 816 write8(wasm::WASM_OPCODE_END); 817 encodeULEB128(Segment.Data.size(), getStream()); // size 818 Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset); 819 writeBytes(Segment.Data); // data 820 } 821 822 // Apply fixups. 823 applyRelocations(DataRelocations, Section.ContentsOffset); 824 825 endSection(Section); 826 } 827 828 void WasmObjectWriter::writeCodeRelocSection() { 829 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md 830 // for descriptions of the reloc sections. 831 832 if (CodeRelocations.empty()) 833 return; 834 835 SectionBookkeeping Section; 836 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); 837 838 encodeULEB128(wasm::WASM_SEC_CODE, getStream()); 839 encodeULEB128(CodeRelocations.size(), getStream()); 840 841 writeRelocations(CodeRelocations); 842 843 endSection(Section); 844 } 845 846 void WasmObjectWriter::writeDataRelocSection() { 847 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md 848 // for descriptions of the reloc sections. 849 850 if (DataRelocations.empty()) 851 return; 852 853 SectionBookkeeping Section; 854 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); 855 856 encodeULEB128(wasm::WASM_SEC_DATA, getStream()); 857 encodeULEB128(DataRelocations.size(), getStream()); 858 859 writeRelocations(DataRelocations); 860 861 endSection(Section); 862 } 863 864 void WasmObjectWriter::writeLinkingMetaDataSection( 865 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, 866 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, 867 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) { 868 SectionBookkeeping Section; 869 startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); 870 SectionBookkeeping SubSection; 871 872 if (SymbolInfos.size() != 0) { 873 startSection(SubSection, wasm::WASM_SYMBOL_TABLE); 874 encodeULEB128(SymbolInfos.size(), getStream()); 875 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) { 876 encodeULEB128(Sym.Kind, getStream()); 877 encodeULEB128(Sym.Flags, getStream()); 878 switch (Sym.Kind) { 879 case wasm::WASM_SYMBOL_TYPE_FUNCTION: 880 case wasm::WASM_SYMBOL_TYPE_GLOBAL: 881 encodeULEB128(Sym.ElementIndex, getStream()); 882 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) 883 writeString(Sym.Name); 884 break; 885 case wasm::WASM_SYMBOL_TYPE_DATA: 886 writeString(Sym.Name); 887 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { 888 encodeULEB128(Sym.DataRef.Segment, getStream()); 889 encodeULEB128(Sym.DataRef.Offset, getStream()); 890 encodeULEB128(Sym.DataRef.Size, getStream()); 891 } 892 break; 893 default: 894 llvm_unreachable("unexpected kind"); 895 } 896 } 897 endSection(SubSection); 898 } 899 900 if (DataSegments.size()) { 901 startSection(SubSection, wasm::WASM_SEGMENT_INFO); 902 encodeULEB128(DataSegments.size(), getStream()); 903 for (const WasmDataSegment &Segment : DataSegments) { 904 writeString(Segment.Name); 905 encodeULEB128(Segment.Alignment, getStream()); 906 encodeULEB128(Segment.Flags, getStream()); 907 } 908 endSection(SubSection); 909 } 910 911 if (!InitFuncs.empty()) { 912 startSection(SubSection, wasm::WASM_INIT_FUNCS); 913 encodeULEB128(InitFuncs.size(), getStream()); 914 for (auto &StartFunc : InitFuncs) { 915 encodeULEB128(StartFunc.first, getStream()); // priority 916 encodeULEB128(StartFunc.second, getStream()); // function index 917 } 918 endSection(SubSection); 919 } 920 921 if (Comdats.size()) { 922 startSection(SubSection, wasm::WASM_COMDAT_INFO); 923 encodeULEB128(Comdats.size(), getStream()); 924 for (const auto &C : Comdats) { 925 writeString(C.first); 926 encodeULEB128(0, getStream()); // flags for future use 927 encodeULEB128(C.second.size(), getStream()); 928 for (const WasmComdatEntry &Entry : C.second) { 929 encodeULEB128(Entry.Kind, getStream()); 930 encodeULEB128(Entry.Index, getStream()); 931 } 932 } 933 endSection(SubSection); 934 } 935 936 endSection(Section); 937 } 938 939 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { 940 assert(Symbol.isFunction()); 941 assert(TypeIndices.count(&Symbol)); 942 return TypeIndices[&Symbol]; 943 } 944 945 uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) { 946 assert(Symbol.isFunction()); 947 948 WasmFunctionType F; 949 const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol); 950 F.Returns = ResolvedSym->getReturns(); 951 F.Params = ResolvedSym->getParams(); 952 953 auto Pair = 954 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 955 if (Pair.second) 956 FunctionTypes.push_back(F); 957 TypeIndices[&Symbol] = Pair.first->second; 958 959 DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n"); 960 DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); 961 return Pair.first->second; 962 } 963 964 void WasmObjectWriter::writeObject(MCAssembler &Asm, 965 const MCAsmLayout &Layout) { 966 DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); 967 MCContext &Ctx = Asm.getContext(); 968 969 // Collect information from the available symbols. 970 SmallVector<WasmFunction, 4> Functions; 971 SmallVector<uint32_t, 4> TableElems; 972 SmallVector<wasm::WasmImport, 4> Imports; 973 SmallVector<wasm::WasmExport, 4> Exports; 974 SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; 975 SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; 976 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; 977 uint32_t DataSize = 0; 978 979 // For now, always emit the memory import, since loads and stores are not 980 // valid without it. In the future, we could perhaps be more clever and omit 981 // it if there are no loads or stores. 982 MCSymbolWasm *MemorySym = 983 cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory")); 984 wasm::WasmImport MemImport; 985 MemImport.Module = MemorySym->getModuleName(); 986 MemImport.Field = MemorySym->getName(); 987 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; 988 Imports.push_back(MemImport); 989 990 // For now, always emit the table section, since indirect calls are not 991 // valid without it. In the future, we could perhaps be more clever and omit 992 // it if there are no indirect calls. 993 MCSymbolWasm *TableSym = 994 cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table")); 995 wasm::WasmImport TableImport; 996 TableImport.Module = TableSym->getModuleName(); 997 TableImport.Field = TableSym->getName(); 998 TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; 999 TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC; 1000 Imports.push_back(TableImport); 1001 1002 // Populate FunctionTypeIndices, and Imports and WasmIndices for undefined 1003 // symbols. This must be done before populating WasmIndices for defined 1004 // symbols. 1005 for (const MCSymbol &S : Asm.symbols()) { 1006 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1007 1008 // Register types for all functions, including those with private linkage 1009 // (because wasm always needs a type signature). 1010 if (WS.isFunction()) 1011 registerFunctionType(WS); 1012 1013 if (WS.isTemporary()) 1014 continue; 1015 1016 // If the symbol is not defined in this translation unit, import it. 1017 if (!WS.isDefined() && !WS.isComdat()) { 1018 if (WS.isFunction()) { 1019 wasm::WasmImport Import; 1020 Import.Module = WS.getModuleName(); 1021 Import.Field = WS.getName(); 1022 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; 1023 Import.SigIndex = getFunctionType(WS); 1024 Imports.push_back(Import); 1025 WasmIndices[&WS] = NumFunctionImports++; 1026 } else if (WS.isGlobal()) { 1027 if (WS.isWeak()) 1028 report_fatal_error("undefined global symbol cannot be weak"); 1029 1030 wasm::WasmImport Import; 1031 Import.Module = WS.getModuleName(); 1032 Import.Field = WS.getName(); 1033 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; 1034 Import.Global = WS.getGlobalType(); 1035 Imports.push_back(Import); 1036 WasmIndices[&WS] = NumGlobalImports++; 1037 } 1038 } 1039 } 1040 1041 // Populate DataSegments, which must be done before populating DataLocations. 1042 for (MCSection &Sec : Asm) { 1043 auto &Section = static_cast<MCSectionWasm &>(Sec); 1044 if (!Section.isWasmData()) 1045 continue; 1046 1047 // .init_array sections are handled specially elsewhere. 1048 if (cast<MCSectionWasm>(Sec).getSectionName().startswith(".init_array")) 1049 continue; 1050 1051 uint32_t SegmentIndex = DataSegments.size(); 1052 DataSize = alignTo(DataSize, Section.getAlignment()); 1053 DataSegments.emplace_back(); 1054 WasmDataSegment &Segment = DataSegments.back(); 1055 Segment.Name = Section.getSectionName(); 1056 Segment.Offset = DataSize; 1057 Segment.Section = &Section; 1058 addData(Segment.Data, Section); 1059 Segment.Alignment = Section.getAlignment(); 1060 Segment.Flags = 0; 1061 DataSize += Segment.Data.size(); 1062 Section.setSegmentIndex(SegmentIndex); 1063 1064 if (const MCSymbolWasm *C = Section.getGroup()) { 1065 Comdats[C->getName()].emplace_back( 1066 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex}); 1067 } 1068 } 1069 1070 // Populate WasmIndices and DataLocations for defined symbols. 1071 for (const MCSymbol &S : Asm.symbols()) { 1072 // Ignore unnamed temporary symbols, which aren't ever exported, imported, 1073 // or used in relocations. 1074 if (S.isTemporary() && S.getName().empty()) 1075 continue; 1076 1077 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1078 DEBUG(dbgs() << "MCSymbol: '" << S << "'" 1079 << " isDefined=" << S.isDefined() 1080 << " isExternal=" << S.isExternal() 1081 << " isTemporary=" << S.isTemporary() 1082 << " isFunction=" << WS.isFunction() 1083 << " isWeak=" << WS.isWeak() 1084 << " isHidden=" << WS.isHidden() 1085 << " isVariable=" << WS.isVariable() << "\n"); 1086 1087 if (WS.isVariable()) 1088 continue; 1089 if (WS.isComdat() && !WS.isDefined()) 1090 continue; 1091 1092 if (WS.isFunction()) { 1093 unsigned Index; 1094 if (WS.isDefined()) { 1095 if (WS.getOffset() != 0) 1096 report_fatal_error( 1097 "function sections must contain one function each"); 1098 1099 if (WS.getSize() == 0) 1100 report_fatal_error( 1101 "function symbols must have a size set with .size"); 1102 1103 // A definition. Write out the function body. 1104 Index = NumFunctionImports + Functions.size(); 1105 WasmFunction Func; 1106 Func.Type = getFunctionType(WS); 1107 Func.Sym = &WS; 1108 WasmIndices[&WS] = Index; 1109 Functions.push_back(Func); 1110 1111 auto &Section = static_cast<MCSectionWasm &>(WS.getSection()); 1112 if (const MCSymbolWasm *C = Section.getGroup()) { 1113 Comdats[C->getName()].emplace_back( 1114 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); 1115 } 1116 } else { 1117 // An import; the index was assigned above. 1118 Index = WasmIndices.find(&WS)->second; 1119 } 1120 1121 DEBUG(dbgs() << " -> function index: " << Index << "\n"); 1122 } else if (WS.isData()) { 1123 if (WS.isTemporary() && !WS.getSize()) 1124 continue; 1125 1126 if (!WS.isDefined()) { 1127 DEBUG(dbgs() << " -> segment index: -1"); 1128 continue; 1129 } 1130 1131 if (!WS.getSize()) 1132 report_fatal_error("data symbols must have a size set with .size: " + 1133 WS.getName()); 1134 1135 int64_t Size = 0; 1136 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) 1137 report_fatal_error(".size expression must be evaluatable"); 1138 1139 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); 1140 assert(DataSection.isWasmData()); 1141 1142 // For each data symbol, export it in the symtab as a reference to the 1143 // corresponding Wasm data segment. 1144 wasm::WasmDataReference Ref = wasm::WasmDataReference{ 1145 DataSection.getSegmentIndex(), 1146 static_cast<uint32_t>(Layout.getSymbolOffset(WS)), 1147 static_cast<uint32_t>(Size)}; 1148 DataLocations[&WS] = Ref; 1149 DEBUG(dbgs() << " -> segment index: " << Ref.Segment); 1150 } else { 1151 // A "true" Wasm global (currently just __stack_pointer) 1152 if (WS.isDefined()) 1153 report_fatal_error("don't yet support defined globals"); 1154 1155 // An import; the index was assigned above 1156 DEBUG(dbgs() << " -> global index: " << WasmIndices.find(&WS)->second 1157 << "\n"); 1158 } 1159 } 1160 1161 // Populate WasmIndices and DataLocations for aliased symbols. We need to 1162 // process these in a separate pass because we need to have processed the 1163 // target of the alias before the alias itself and the symbols are not 1164 // necessarily ordered in this way. 1165 for (const MCSymbol &S : Asm.symbols()) { 1166 if (!S.isVariable()) 1167 continue; 1168 1169 assert(S.isDefined()); 1170 1171 // Find the target symbol of this weak alias and export that index 1172 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1173 const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); 1174 DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); 1175 1176 if (WS.isFunction()) { 1177 assert(WasmIndices.count(ResolvedSym) > 0); 1178 uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; 1179 WasmIndices[&WS] = WasmIndex; 1180 DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); 1181 } else if (WS.isData()) { 1182 assert(DataLocations.count(ResolvedSym) > 0); 1183 const wasm::WasmDataReference &Ref = 1184 DataLocations.find(ResolvedSym)->second; 1185 DataLocations[&WS] = Ref; 1186 DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); 1187 } else { 1188 report_fatal_error("don't yet support global aliases"); 1189 } 1190 } 1191 1192 // Finally, populate the symbol table itself, in its "natural" order. 1193 for (const MCSymbol &S : Asm.symbols()) { 1194 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1195 if (WS.isTemporary() && WS.getName().empty()) 1196 continue; 1197 if (WS.isComdat() && !WS.isDefined()) 1198 continue; 1199 if (WS.isTemporary() && WS.isData() && !WS.getSize()) 1200 continue; 1201 1202 uint32_t Flags = 0; 1203 if (WS.isWeak()) 1204 Flags |= wasm::WASM_SYMBOL_BINDING_WEAK; 1205 if (WS.isHidden()) 1206 Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN; 1207 if (!WS.isExternal() && WS.isDefined()) 1208 Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; 1209 if (WS.isUndefined()) 1210 Flags |= wasm::WASM_SYMBOL_UNDEFINED; 1211 1212 wasm::WasmSymbolInfo Info; 1213 Info.Name = WS.getName(); 1214 Info.Kind = WS.getType(); 1215 Info.Flags = Flags; 1216 if (!WS.isData()) 1217 Info.ElementIndex = WasmIndices.find(&WS)->second; 1218 else if (WS.isDefined()) 1219 Info.DataRef = DataLocations.find(&WS)->second; 1220 SymbolIndices[&WS] = SymbolInfos.size(); 1221 SymbolInfos.emplace_back(Info); 1222 } 1223 1224 { 1225 auto HandleReloc = [&](const WasmRelocationEntry &Rel) { 1226 // Functions referenced by a relocation need to put in the table. This is 1227 // purely to make the object file's provisional values readable, and is 1228 // ignored by the linker, which re-calculates the relocations itself. 1229 if (Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 && 1230 Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB) 1231 return; 1232 assert(Rel.Symbol->isFunction()); 1233 const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol); 1234 uint32_t FunctionIndex = WasmIndices.find(&WS)->second; 1235 uint32_t TableIndex = TableElems.size() + kInitialTableOffset; 1236 if (TableIndices.try_emplace(&WS, TableIndex).second) { 1237 DEBUG(dbgs() << " -> adding " << WS.getName() 1238 << " to table: " << TableIndex << "\n"); 1239 TableElems.push_back(FunctionIndex); 1240 registerFunctionType(WS); 1241 } 1242 }; 1243 1244 for (const WasmRelocationEntry &RelEntry : CodeRelocations) 1245 HandleReloc(RelEntry); 1246 for (const WasmRelocationEntry &RelEntry : DataRelocations) 1247 HandleReloc(RelEntry); 1248 } 1249 1250 // Translate .init_array section contents into start functions. 1251 for (const MCSection &S : Asm) { 1252 const auto &WS = static_cast<const MCSectionWasm &>(S); 1253 if (WS.getSectionName().startswith(".fini_array")) 1254 report_fatal_error(".fini_array sections are unsupported"); 1255 if (!WS.getSectionName().startswith(".init_array")) 1256 continue; 1257 if (WS.getFragmentList().empty()) 1258 continue; 1259 if (WS.getFragmentList().size() != 2) 1260 report_fatal_error("only one .init_array section fragment supported"); 1261 const MCFragment &AlignFrag = *WS.begin(); 1262 if (AlignFrag.getKind() != MCFragment::FT_Align) 1263 report_fatal_error(".init_array section should be aligned"); 1264 if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4)) 1265 report_fatal_error(".init_array section should be aligned for pointers"); 1266 const MCFragment &Frag = *std::next(WS.begin()); 1267 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) 1268 report_fatal_error("only data supported in .init_array section"); 1269 uint16_t Priority = UINT16_MAX; 1270 if (WS.getSectionName().size() != 11) { 1271 if (WS.getSectionName()[11] != '.') 1272 report_fatal_error(".init_array section priority should start with '.'"); 1273 if (WS.getSectionName().substr(12).getAsInteger(10, Priority)) 1274 report_fatal_error("invalid .init_array section priority"); 1275 } 1276 const auto &DataFrag = cast<MCDataFragment>(Frag); 1277 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 1278 for (const uint8_t *p = (const uint8_t *)Contents.data(), 1279 *end = (const uint8_t *)Contents.data() + Contents.size(); 1280 p != end; ++p) { 1281 if (*p != 0) 1282 report_fatal_error("non-symbolic data in .init_array section"); 1283 } 1284 for (const MCFixup &Fixup : DataFrag.getFixups()) { 1285 assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false)); 1286 const MCExpr *Expr = Fixup.getValue(); 1287 auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr); 1288 if (!Sym) 1289 report_fatal_error("fixups in .init_array should be symbol references"); 1290 if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION) 1291 report_fatal_error("symbols in .init_array should be for functions"); 1292 auto I = SymbolIndices.find(cast<MCSymbolWasm>(&Sym->getSymbol())); 1293 if (I == SymbolIndices.end()) 1294 report_fatal_error("symbols in .init_array should be defined"); 1295 uint32_t Index = I->second; 1296 InitFuncs.push_back(std::make_pair(Priority, Index)); 1297 } 1298 } 1299 1300 // Write out the Wasm header. 1301 writeHeader(Asm); 1302 1303 writeTypeSection(FunctionTypes); 1304 writeImportSection(Imports, DataSize, TableElems.size()); 1305 writeFunctionSection(Functions); 1306 // Skip the "table" section; we import the table instead. 1307 // Skip the "memory" section; we import the memory instead. 1308 writeGlobalSection(); 1309 writeExportSection(Exports); 1310 writeElemSection(TableElems); 1311 writeCodeSection(Asm, Layout, Functions); 1312 writeDataSection(); 1313 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); 1314 writeCodeRelocSection(); 1315 writeDataRelocSection(); 1316 1317 // TODO: Translate the .comment section to the output. 1318 // TODO: Translate debug sections to the output. 1319 } 1320 1321 std::unique_ptr<MCObjectWriter> 1322 llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, 1323 raw_pwrite_stream &OS) { 1324 return llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS); 1325 } 1326