1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// 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 // This file implements Wasm object file writer information. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/ADT/STLExtras.h" 14 #include "llvm/ADT/SmallPtrSet.h" 15 #include "llvm/BinaryFormat/Wasm.h" 16 #include "llvm/BinaryFormat/WasmTraits.h" 17 #include "llvm/Config/llvm-config.h" 18 #include "llvm/MC/MCAsmBackend.h" 19 #include "llvm/MC/MCAsmLayout.h" 20 #include "llvm/MC/MCAssembler.h" 21 #include "llvm/MC/MCContext.h" 22 #include "llvm/MC/MCExpr.h" 23 #include "llvm/MC/MCFixupKindInfo.h" 24 #include "llvm/MC/MCObjectWriter.h" 25 #include "llvm/MC/MCSectionWasm.h" 26 #include "llvm/MC/MCSymbolWasm.h" 27 #include "llvm/MC/MCValue.h" 28 #include "llvm/MC/MCWasmObjectWriter.h" 29 #include "llvm/Support/Casting.h" 30 #include "llvm/Support/Debug.h" 31 #include "llvm/Support/EndianStream.h" 32 #include "llvm/Support/ErrorHandling.h" 33 #include "llvm/Support/LEB128.h" 34 #include "llvm/Support/StringSaver.h" 35 #include <vector> 36 37 using namespace llvm; 38 39 #define DEBUG_TYPE "mc" 40 41 namespace { 42 43 // When we create the indirect function table we start at 1, so that there is 44 // and empty slot at 0 and therefore calling a null function pointer will trap. 45 static const uint32_t InitialTableOffset = 1; 46 47 // For patching purposes, we need to remember where each section starts, both 48 // for patching up the section size field, and for patching up references to 49 // locations within the section. 50 struct SectionBookkeeping { 51 // Where the size of the section is written. 52 uint64_t SizeOffset; 53 // Where the section header ends (without custom section name). 54 uint64_t PayloadOffset; 55 // Where the contents of the section starts. 56 uint64_t ContentsOffset; 57 uint32_t Index; 58 }; 59 60 // A wasm data segment. A wasm binary contains only a single data section 61 // but that can contain many segments, each with their own virtual location 62 // in memory. Each MCSection data created by llvm is modeled as its own 63 // wasm data segment. 64 struct WasmDataSegment { 65 MCSectionWasm *Section; 66 StringRef Name; 67 uint32_t InitFlags; 68 uint64_t Offset; 69 uint32_t Alignment; 70 uint32_t LinkerFlags; 71 SmallVector<char, 4> Data; 72 }; 73 74 // A wasm function to be written into the function section. 75 struct WasmFunction { 76 uint32_t SigIndex; 77 const MCSymbolWasm *Sym; 78 }; 79 80 // A wasm global to be written into the global section. 81 struct WasmGlobal { 82 wasm::WasmGlobalType Type; 83 uint64_t InitialValue; 84 }; 85 86 // Information about a single item which is part of a COMDAT. For each data 87 // segment or function which is in the COMDAT, there is a corresponding 88 // WasmComdatEntry. 89 struct WasmComdatEntry { 90 unsigned Kind; 91 uint32_t Index; 92 }; 93 94 // Information about a single relocation. 95 struct WasmRelocationEntry { 96 uint64_t Offset; // Where is the relocation. 97 const MCSymbolWasm *Symbol; // The symbol to relocate with. 98 int64_t Addend; // A value to add to the symbol. 99 unsigned Type; // The type of the relocation. 100 const MCSectionWasm *FixupSection; // The section the relocation is targeting. 101 102 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, 103 int64_t Addend, unsigned Type, 104 const MCSectionWasm *FixupSection) 105 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), 106 FixupSection(FixupSection) {} 107 108 bool hasAddend() const { return wasm::relocTypeHasAddend(Type); } 109 110 void print(raw_ostream &Out) const { 111 Out << wasm::relocTypetoString(Type) << " Off=" << Offset 112 << ", Sym=" << *Symbol << ", Addend=" << Addend 113 << ", FixupSection=" << FixupSection->getName(); 114 } 115 116 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 117 LLVM_DUMP_METHOD void dump() const { print(dbgs()); } 118 #endif 119 }; 120 121 static const uint32_t InvalidIndex = -1; 122 123 struct WasmCustomSection { 124 125 StringRef Name; 126 MCSectionWasm *Section; 127 128 uint32_t OutputContentsOffset; 129 uint32_t OutputIndex; 130 131 WasmCustomSection(StringRef Name, MCSectionWasm *Section) 132 : Name(Name), Section(Section), OutputContentsOffset(0), 133 OutputIndex(InvalidIndex) {} 134 }; 135 136 #if !defined(NDEBUG) 137 raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { 138 Rel.print(OS); 139 return OS; 140 } 141 #endif 142 143 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded 144 // to allow patching. 145 template <int W> 146 void writePatchableLEB(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) { 147 uint8_t Buffer[W]; 148 unsigned SizeLen = encodeULEB128(X, Buffer, W); 149 assert(SizeLen == W); 150 Stream.pwrite((char *)Buffer, SizeLen, Offset); 151 } 152 153 // Write X as an signed LEB value at offset Offset in Stream, padded 154 // to allow patching. 155 template <int W> 156 void writePatchableSLEB(raw_pwrite_stream &Stream, int64_t X, uint64_t Offset) { 157 uint8_t Buffer[W]; 158 unsigned SizeLen = encodeSLEB128(X, Buffer, W); 159 assert(SizeLen == W); 160 Stream.pwrite((char *)Buffer, SizeLen, Offset); 161 } 162 163 // Write X as a plain integer value at offset Offset in Stream. 164 static void patchI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 165 uint8_t Buffer[4]; 166 support::endian::write32le(Buffer, X); 167 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); 168 } 169 170 static void patchI64(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) { 171 uint8_t Buffer[8]; 172 support::endian::write64le(Buffer, X); 173 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); 174 } 175 176 bool isDwoSection(const MCSection &Sec) { 177 return Sec.getName().endswith(".dwo"); 178 } 179 180 class WasmObjectWriter : public MCObjectWriter { 181 support::endian::Writer *W; 182 183 /// The target specific Wasm writer instance. 184 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter; 185 186 // Relocations for fixing up references in the code section. 187 std::vector<WasmRelocationEntry> CodeRelocations; 188 // Relocations for fixing up references in the data section. 189 std::vector<WasmRelocationEntry> DataRelocations; 190 191 // Index values to use for fixing up call_indirect type indices. 192 // Maps function symbols to the index of the type of the function 193 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices; 194 // Maps function symbols to the table element index space. Used 195 // for TABLE_INDEX relocation types (i.e. address taken functions). 196 DenseMap<const MCSymbolWasm *, uint32_t> TableIndices; 197 // Maps function/global/table symbols to the 198 // function/global/table/event/section index space. 199 DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; 200 DenseMap<const MCSymbolWasm *, uint32_t> GOTIndices; 201 // Maps data symbols to the Wasm segment and offset/size with the segment. 202 DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; 203 204 // Stores output data (index, relocations, content offset) for custom 205 // section. 206 std::vector<WasmCustomSection> CustomSections; 207 std::unique_ptr<WasmCustomSection> ProducersSection; 208 std::unique_ptr<WasmCustomSection> TargetFeaturesSection; 209 // Relocations for fixing up references in the custom sections. 210 DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>> 211 CustomSectionsRelocations; 212 213 // Map from section to defining function symbol. 214 DenseMap<const MCSection *, const MCSymbol *> SectionFunctions; 215 216 DenseMap<wasm::WasmSignature, uint32_t> SignatureIndices; 217 SmallVector<wasm::WasmSignature, 4> Signatures; 218 SmallVector<WasmDataSegment, 4> DataSegments; 219 unsigned NumFunctionImports = 0; 220 unsigned NumGlobalImports = 0; 221 unsigned NumTableImports = 0; 222 unsigned NumEventImports = 0; 223 uint32_t SectionCount = 0; 224 225 enum class DwoMode { 226 AllSections, 227 NonDwoOnly, 228 DwoOnly, 229 }; 230 bool IsSplitDwarf = false; 231 raw_pwrite_stream *OS = nullptr; 232 raw_pwrite_stream *DwoOS = nullptr; 233 234 // TargetObjectWriter wranppers. 235 bool is64Bit() const { return TargetObjectWriter->is64Bit(); } 236 bool isEmscripten() const { return TargetObjectWriter->isEmscripten(); } 237 238 void startSection(SectionBookkeeping &Section, unsigned SectionId); 239 void startCustomSection(SectionBookkeeping &Section, StringRef Name); 240 void endSection(SectionBookkeeping &Section); 241 242 public: 243 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, 244 raw_pwrite_stream &OS_) 245 : TargetObjectWriter(std::move(MOTW)), OS(&OS_) {} 246 247 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, 248 raw_pwrite_stream &OS_, raw_pwrite_stream &DwoOS_) 249 : TargetObjectWriter(std::move(MOTW)), IsSplitDwarf(true), OS(&OS_), 250 DwoOS(&DwoOS_) {} 251 252 private: 253 void reset() override { 254 CodeRelocations.clear(); 255 DataRelocations.clear(); 256 TypeIndices.clear(); 257 WasmIndices.clear(); 258 GOTIndices.clear(); 259 TableIndices.clear(); 260 DataLocations.clear(); 261 CustomSections.clear(); 262 ProducersSection.reset(); 263 TargetFeaturesSection.reset(); 264 CustomSectionsRelocations.clear(); 265 SignatureIndices.clear(); 266 Signatures.clear(); 267 DataSegments.clear(); 268 SectionFunctions.clear(); 269 NumFunctionImports = 0; 270 NumGlobalImports = 0; 271 NumTableImports = 0; 272 MCObjectWriter::reset(); 273 } 274 275 void writeHeader(const MCAssembler &Asm); 276 277 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 278 const MCFragment *Fragment, const MCFixup &Fixup, 279 MCValue Target, uint64_t &FixedValue) override; 280 281 void executePostLayoutBinding(MCAssembler &Asm, 282 const MCAsmLayout &Layout) override; 283 void prepareImports(SmallVectorImpl<wasm::WasmImport> &Imports, 284 MCAssembler &Asm, const MCAsmLayout &Layout); 285 uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; 286 287 uint64_t writeOneObject(MCAssembler &Asm, const MCAsmLayout &Layout, 288 DwoMode Mode); 289 290 void writeString(const StringRef Str) { 291 encodeULEB128(Str.size(), W->OS); 292 W->OS << Str; 293 } 294 295 void writeI32(int32_t val) { 296 char Buffer[4]; 297 support::endian::write32le(Buffer, val); 298 W->OS.write(Buffer, sizeof(Buffer)); 299 } 300 301 void writeI64(int64_t val) { 302 char Buffer[8]; 303 support::endian::write64le(Buffer, val); 304 W->OS.write(Buffer, sizeof(Buffer)); 305 } 306 307 void writeValueType(wasm::ValType Ty) { W->OS << static_cast<char>(Ty); } 308 309 void writeTypeSection(ArrayRef<wasm::WasmSignature> Signatures); 310 void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint64_t DataSize, 311 uint32_t NumElements); 312 void writeFunctionSection(ArrayRef<WasmFunction> Functions); 313 void writeExportSection(ArrayRef<wasm::WasmExport> Exports); 314 void writeElemSection(ArrayRef<uint32_t> TableElems); 315 void writeDataCountSection(); 316 uint32_t writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, 317 ArrayRef<WasmFunction> Functions); 318 uint32_t writeDataSection(const MCAsmLayout &Layout); 319 void writeEventSection(ArrayRef<wasm::WasmEventType> Events); 320 void writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals); 321 void writeTableSection(ArrayRef<wasm::WasmTable> Tables); 322 void writeRelocSection(uint32_t SectionIndex, StringRef Name, 323 std::vector<WasmRelocationEntry> &Relocations); 324 void writeLinkingMetaDataSection( 325 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, 326 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, 327 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats); 328 void writeCustomSection(WasmCustomSection &CustomSection, 329 const MCAssembler &Asm, const MCAsmLayout &Layout); 330 void writeCustomRelocSections(); 331 332 uint64_t getProvisionalValue(const WasmRelocationEntry &RelEntry, 333 const MCAsmLayout &Layout); 334 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, 335 uint64_t ContentsOffset, const MCAsmLayout &Layout); 336 337 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); 338 uint32_t getFunctionType(const MCSymbolWasm &Symbol); 339 uint32_t getEventType(const MCSymbolWasm &Symbol); 340 void registerFunctionType(const MCSymbolWasm &Symbol); 341 void registerEventType(const MCSymbolWasm &Symbol); 342 }; 343 344 } // end anonymous namespace 345 346 // Write out a section header and a patchable section size field. 347 void WasmObjectWriter::startSection(SectionBookkeeping &Section, 348 unsigned SectionId) { 349 LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n"); 350 W->OS << char(SectionId); 351 352 Section.SizeOffset = W->OS.tell(); 353 354 // The section size. We don't know the size yet, so reserve enough space 355 // for any 32-bit value; we'll patch it later. 356 encodeULEB128(0, W->OS, 5); 357 358 // The position where the section starts, for measuring its size. 359 Section.ContentsOffset = W->OS.tell(); 360 Section.PayloadOffset = W->OS.tell(); 361 Section.Index = SectionCount++; 362 } 363 364 void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section, 365 StringRef Name) { 366 LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n"); 367 startSection(Section, wasm::WASM_SEC_CUSTOM); 368 369 // The position where the section header ends, for measuring its size. 370 Section.PayloadOffset = W->OS.tell(); 371 372 // Custom sections in wasm also have a string identifier. 373 writeString(Name); 374 375 // The position where the custom section starts. 376 Section.ContentsOffset = W->OS.tell(); 377 } 378 379 // Now that the section is complete and we know how big it is, patch up the 380 // section size field at the start of the section. 381 void WasmObjectWriter::endSection(SectionBookkeeping &Section) { 382 uint64_t Size = W->OS.tell(); 383 // /dev/null doesn't support seek/tell and can report offset of 0. 384 // Simply skip this patching in that case. 385 if (!Size) 386 return; 387 388 Size -= Section.PayloadOffset; 389 if (uint32_t(Size) != Size) 390 report_fatal_error("section size does not fit in a uint32_t"); 391 392 LLVM_DEBUG(dbgs() << "endSection size=" << Size << "\n"); 393 394 // Write the final section size to the payload_len field, which follows 395 // the section id byte. 396 writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W->OS), Size, 397 Section.SizeOffset); 398 } 399 400 // Emit the Wasm header. 401 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { 402 W->OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic)); 403 W->write<uint32_t>(wasm::WasmVersion); 404 } 405 406 void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, 407 const MCAsmLayout &Layout) { 408 // Some compilation units require the indirect function table to be present 409 // but don't explicitly reference it. This is the case for call_indirect 410 // without the reference-types feature, and also function bitcasts in all 411 // cases. In those cases the __indirect_function_table has the 412 // WASM_SYMBOL_NO_STRIP attribute. Here we make sure this symbol makes it to 413 // the assembler, if needed. 414 if (auto *Sym = Asm.getContext().lookupSymbol("__indirect_function_table")) { 415 const auto *WasmSym = static_cast<const MCSymbolWasm *>(Sym); 416 if (WasmSym->isNoStrip()) 417 Asm.registerSymbol(*Sym); 418 } 419 420 // Build a map of sections to the function that defines them, for use 421 // in recordRelocation. 422 for (const MCSymbol &S : Asm.symbols()) { 423 const auto &WS = static_cast<const MCSymbolWasm &>(S); 424 if (WS.isDefined() && WS.isFunction() && !WS.isVariable()) { 425 const auto &Sec = static_cast<const MCSectionWasm &>(S.getSection()); 426 auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S)); 427 if (!Pair.second) 428 report_fatal_error("section already has a defining function: " + 429 Sec.getName()); 430 } 431 } 432 } 433 434 void WasmObjectWriter::recordRelocation(MCAssembler &Asm, 435 const MCAsmLayout &Layout, 436 const MCFragment *Fragment, 437 const MCFixup &Fixup, MCValue Target, 438 uint64_t &FixedValue) { 439 // The WebAssembly backend should never generate FKF_IsPCRel fixups 440 assert(!(Asm.getBackend().getFixupKindInfo(Fixup.getKind()).Flags & 441 MCFixupKindInfo::FKF_IsPCRel)); 442 443 const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent()); 444 uint64_t C = Target.getConstant(); 445 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 446 MCContext &Ctx = Asm.getContext(); 447 448 if (const MCSymbolRefExpr *RefB = Target.getSymB()) { 449 // To get here the A - B expression must have failed evaluateAsRelocatable. 450 // This means either A or B must be undefined and in WebAssembly we can't 451 // support either of those cases. 452 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol()); 453 Ctx.reportError( 454 Fixup.getLoc(), 455 Twine("symbol '") + SymB.getName() + 456 "': unsupported subtraction expression used in relocation."); 457 return; 458 } 459 460 // We either rejected the fixup or folded B into C at this point. 461 const MCSymbolRefExpr *RefA = Target.getSymA(); 462 const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol()); 463 464 // The .init_array isn't translated as data, so don't do relocations in it. 465 if (FixupSection.getName().startswith(".init_array")) { 466 SymA->setUsedInInitArray(); 467 return; 468 } 469 470 if (SymA->isVariable()) { 471 const MCExpr *Expr = SymA->getVariableValue(); 472 if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) 473 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) 474 llvm_unreachable("weakref used in reloc not yet implemented"); 475 } 476 477 // Put any constant offset in an addend. Offsets can be negative, and 478 // LLVM expects wrapping, in contrast to wasm's immediates which can't 479 // be negative and don't wrap. 480 FixedValue = 0; 481 482 unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup); 483 484 // Absolute offset within a section or a function. 485 // Currently only supported for for metadata sections. 486 // See: test/MC/WebAssembly/blockaddress.ll 487 if (Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || 488 Type == wasm::R_WASM_FUNCTION_OFFSET_I64 || 489 Type == wasm::R_WASM_SECTION_OFFSET_I32) { 490 if (!FixupSection.getKind().isMetadata()) 491 report_fatal_error("relocations for function or section offsets are " 492 "only supported in metadata sections"); 493 494 const MCSymbol *SectionSymbol = nullptr; 495 const MCSection &SecA = SymA->getSection(); 496 if (SecA.getKind().isText()) { 497 auto SecSymIt = SectionFunctions.find(&SecA); 498 if (SecSymIt == SectionFunctions.end()) 499 report_fatal_error("section doesn\'t have defining symbol"); 500 SectionSymbol = SecSymIt->second; 501 } else { 502 SectionSymbol = SecA.getBeginSymbol(); 503 } 504 if (!SectionSymbol) 505 report_fatal_error("section symbol is required for relocation"); 506 507 C += Layout.getSymbolOffset(*SymA); 508 SymA = cast<MCSymbolWasm>(SectionSymbol); 509 } 510 511 if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB || 512 Type == wasm::R_WASM_TABLE_INDEX_SLEB || 513 Type == wasm::R_WASM_TABLE_INDEX_SLEB64 || 514 Type == wasm::R_WASM_TABLE_INDEX_I32 || 515 Type == wasm::R_WASM_TABLE_INDEX_I64) { 516 // TABLE_INDEX relocs implicitly use the default indirect function table. 517 // We require the function table to have already been defined. 518 auto TableName = "__indirect_function_table"; 519 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(TableName)); 520 if (!Sym || !Sym->isFunctionTable()) { 521 Ctx.reportError( 522 Fixup.getLoc(), 523 "symbol '__indirect_function_table' is not a function table"); 524 } else { 525 // Ensure that __indirect_function_table reaches the output. 526 Sym->setNoStrip(); 527 Asm.registerSymbol(*Sym); 528 } 529 } 530 531 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be 532 // against a named symbol. 533 if (Type != wasm::R_WASM_TYPE_INDEX_LEB) { 534 if (SymA->getName().empty()) 535 report_fatal_error("relocations against un-named temporaries are not yet " 536 "supported by wasm"); 537 538 SymA->setUsedInReloc(); 539 } 540 541 if (RefA->getKind() == MCSymbolRefExpr::VK_GOT) 542 SymA->setUsedInGOT(); 543 544 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); 545 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); 546 547 if (FixupSection.isWasmData()) { 548 DataRelocations.push_back(Rec); 549 } else if (FixupSection.getKind().isText()) { 550 CodeRelocations.push_back(Rec); 551 } else if (FixupSection.getKind().isMetadata()) { 552 CustomSectionsRelocations[&FixupSection].push_back(Rec); 553 } else { 554 llvm_unreachable("unexpected section type"); 555 } 556 } 557 558 // Compute a value to write into the code at the location covered 559 // by RelEntry. This value isn't used by the static linker; it just serves 560 // to make the object format more readable and more likely to be directly 561 // useable. 562 uint64_t 563 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry, 564 const MCAsmLayout &Layout) { 565 if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB || 566 RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) && 567 !RelEntry.Symbol->isGlobal()) { 568 assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space"); 569 return GOTIndices[RelEntry.Symbol]; 570 } 571 572 switch (RelEntry.Type) { 573 case wasm::R_WASM_TABLE_INDEX_REL_SLEB: 574 case wasm::R_WASM_TABLE_INDEX_SLEB: 575 case wasm::R_WASM_TABLE_INDEX_SLEB64: 576 case wasm::R_WASM_TABLE_INDEX_I32: 577 case wasm::R_WASM_TABLE_INDEX_I64: { 578 // Provisional value is table address of the resolved symbol itself 579 const MCSymbolWasm *Base = 580 cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol)); 581 assert(Base->isFunction()); 582 if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB) 583 return TableIndices[Base] - InitialTableOffset; 584 else 585 return TableIndices[Base]; 586 } 587 case wasm::R_WASM_TYPE_INDEX_LEB: 588 // Provisional value is same as the index 589 return getRelocationIndexValue(RelEntry); 590 case wasm::R_WASM_FUNCTION_INDEX_LEB: 591 case wasm::R_WASM_GLOBAL_INDEX_LEB: 592 case wasm::R_WASM_GLOBAL_INDEX_I32: 593 case wasm::R_WASM_EVENT_INDEX_LEB: 594 case wasm::R_WASM_TABLE_NUMBER_LEB: 595 // Provisional value is function/global/event Wasm index 596 assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space"); 597 return WasmIndices[RelEntry.Symbol]; 598 case wasm::R_WASM_FUNCTION_OFFSET_I32: 599 case wasm::R_WASM_FUNCTION_OFFSET_I64: 600 case wasm::R_WASM_SECTION_OFFSET_I32: { 601 const auto &Section = 602 static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection()); 603 return Section.getSectionOffset() + RelEntry.Addend; 604 } 605 case wasm::R_WASM_MEMORY_ADDR_LEB: 606 case wasm::R_WASM_MEMORY_ADDR_LEB64: 607 case wasm::R_WASM_MEMORY_ADDR_SLEB: 608 case wasm::R_WASM_MEMORY_ADDR_SLEB64: 609 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: 610 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: 611 case wasm::R_WASM_MEMORY_ADDR_I32: 612 case wasm::R_WASM_MEMORY_ADDR_I64: 613 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: { 614 // Provisional value is address of the global plus the offset 615 // For undefined symbols, use zero 616 if (!RelEntry.Symbol->isDefined()) 617 return 0; 618 const wasm::WasmDataReference &SymRef = DataLocations[RelEntry.Symbol]; 619 const WasmDataSegment &Segment = DataSegments[SymRef.Segment]; 620 // Ignore overflow. LLVM allows address arithmetic to silently wrap. 621 return Segment.Offset + SymRef.Offset + RelEntry.Addend; 622 } 623 default: 624 llvm_unreachable("invalid relocation type"); 625 } 626 } 627 628 static void addData(SmallVectorImpl<char> &DataBytes, 629 MCSectionWasm &DataSection) { 630 LLVM_DEBUG(errs() << "addData: " << DataSection.getName() << "\n"); 631 632 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); 633 634 for (const MCFragment &Frag : DataSection) { 635 if (Frag.hasInstructions()) 636 report_fatal_error("only data supported in data sections"); 637 638 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) { 639 if (Align->getValueSize() != 1) 640 report_fatal_error("only byte values supported for alignment"); 641 // If nops are requested, use zeros, as this is the data section. 642 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); 643 uint64_t Size = 644 std::min<uint64_t>(alignTo(DataBytes.size(), Align->getAlignment()), 645 DataBytes.size() + Align->getMaxBytesToEmit()); 646 DataBytes.resize(Size, Value); 647 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { 648 int64_t NumValues; 649 if (!Fill->getNumValues().evaluateAsAbsolute(NumValues)) 650 llvm_unreachable("The fill should be an assembler constant"); 651 DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues, 652 Fill->getValue()); 653 } else if (auto *LEB = dyn_cast<MCLEBFragment>(&Frag)) { 654 const SmallVectorImpl<char> &Contents = LEB->getContents(); 655 llvm::append_range(DataBytes, Contents); 656 } else { 657 const auto &DataFrag = cast<MCDataFragment>(Frag); 658 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 659 llvm::append_range(DataBytes, Contents); 660 } 661 } 662 663 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); 664 } 665 666 uint32_t 667 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) { 668 if (RelEntry.Type == wasm::R_WASM_TYPE_INDEX_LEB) { 669 if (!TypeIndices.count(RelEntry.Symbol)) 670 report_fatal_error("symbol not found in type index space: " + 671 RelEntry.Symbol->getName()); 672 return TypeIndices[RelEntry.Symbol]; 673 } 674 675 return RelEntry.Symbol->getIndex(); 676 } 677 678 // Apply the portions of the relocation records that we can handle ourselves 679 // directly. 680 void WasmObjectWriter::applyRelocations( 681 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset, 682 const MCAsmLayout &Layout) { 683 auto &Stream = static_cast<raw_pwrite_stream &>(W->OS); 684 for (const WasmRelocationEntry &RelEntry : Relocations) { 685 uint64_t Offset = ContentsOffset + 686 RelEntry.FixupSection->getSectionOffset() + 687 RelEntry.Offset; 688 689 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); 690 auto Value = getProvisionalValue(RelEntry, Layout); 691 692 switch (RelEntry.Type) { 693 case wasm::R_WASM_FUNCTION_INDEX_LEB: 694 case wasm::R_WASM_TYPE_INDEX_LEB: 695 case wasm::R_WASM_GLOBAL_INDEX_LEB: 696 case wasm::R_WASM_MEMORY_ADDR_LEB: 697 case wasm::R_WASM_EVENT_INDEX_LEB: 698 case wasm::R_WASM_TABLE_NUMBER_LEB: 699 writePatchableLEB<5>(Stream, Value, Offset); 700 break; 701 case wasm::R_WASM_MEMORY_ADDR_LEB64: 702 writePatchableLEB<10>(Stream, Value, Offset); 703 break; 704 case wasm::R_WASM_TABLE_INDEX_I32: 705 case wasm::R_WASM_MEMORY_ADDR_I32: 706 case wasm::R_WASM_FUNCTION_OFFSET_I32: 707 case wasm::R_WASM_SECTION_OFFSET_I32: 708 case wasm::R_WASM_GLOBAL_INDEX_I32: 709 patchI32(Stream, Value, Offset); 710 break; 711 case wasm::R_WASM_TABLE_INDEX_I64: 712 case wasm::R_WASM_MEMORY_ADDR_I64: 713 case wasm::R_WASM_FUNCTION_OFFSET_I64: 714 patchI64(Stream, Value, Offset); 715 break; 716 case wasm::R_WASM_TABLE_INDEX_SLEB: 717 case wasm::R_WASM_TABLE_INDEX_REL_SLEB: 718 case wasm::R_WASM_MEMORY_ADDR_SLEB: 719 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: 720 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: 721 writePatchableSLEB<5>(Stream, Value, Offset); 722 break; 723 case wasm::R_WASM_TABLE_INDEX_SLEB64: 724 case wasm::R_WASM_MEMORY_ADDR_SLEB64: 725 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: 726 writePatchableSLEB<10>(Stream, Value, Offset); 727 break; 728 default: 729 llvm_unreachable("invalid relocation type"); 730 } 731 } 732 } 733 734 void WasmObjectWriter::writeTypeSection( 735 ArrayRef<wasm::WasmSignature> Signatures) { 736 if (Signatures.empty()) 737 return; 738 739 SectionBookkeeping Section; 740 startSection(Section, wasm::WASM_SEC_TYPE); 741 742 encodeULEB128(Signatures.size(), W->OS); 743 744 for (const wasm::WasmSignature &Sig : Signatures) { 745 W->OS << char(wasm::WASM_TYPE_FUNC); 746 encodeULEB128(Sig.Params.size(), W->OS); 747 for (wasm::ValType Ty : Sig.Params) 748 writeValueType(Ty); 749 encodeULEB128(Sig.Returns.size(), W->OS); 750 for (wasm::ValType Ty : Sig.Returns) 751 writeValueType(Ty); 752 } 753 754 endSection(Section); 755 } 756 757 void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports, 758 uint64_t DataSize, 759 uint32_t NumElements) { 760 if (Imports.empty()) 761 return; 762 763 uint64_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; 764 765 SectionBookkeeping Section; 766 startSection(Section, wasm::WASM_SEC_IMPORT); 767 768 encodeULEB128(Imports.size(), W->OS); 769 for (const wasm::WasmImport &Import : Imports) { 770 writeString(Import.Module); 771 writeString(Import.Field); 772 W->OS << char(Import.Kind); 773 774 switch (Import.Kind) { 775 case wasm::WASM_EXTERNAL_FUNCTION: 776 encodeULEB128(Import.SigIndex, W->OS); 777 break; 778 case wasm::WASM_EXTERNAL_GLOBAL: 779 W->OS << char(Import.Global.Type); 780 W->OS << char(Import.Global.Mutable ? 1 : 0); 781 break; 782 case wasm::WASM_EXTERNAL_MEMORY: 783 encodeULEB128(Import.Memory.Flags, W->OS); 784 encodeULEB128(NumPages, W->OS); // initial 785 break; 786 case wasm::WASM_EXTERNAL_TABLE: 787 W->OS << char(Import.Table.ElemType); 788 encodeULEB128(0, W->OS); // flags 789 encodeULEB128(NumElements, W->OS); // initial 790 break; 791 case wasm::WASM_EXTERNAL_EVENT: 792 encodeULEB128(Import.Event.Attribute, W->OS); 793 encodeULEB128(Import.Event.SigIndex, W->OS); 794 break; 795 default: 796 llvm_unreachable("unsupported import kind"); 797 } 798 } 799 800 endSection(Section); 801 } 802 803 void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { 804 if (Functions.empty()) 805 return; 806 807 SectionBookkeeping Section; 808 startSection(Section, wasm::WASM_SEC_FUNCTION); 809 810 encodeULEB128(Functions.size(), W->OS); 811 for (const WasmFunction &Func : Functions) 812 encodeULEB128(Func.SigIndex, W->OS); 813 814 endSection(Section); 815 } 816 817 void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) { 818 if (Events.empty()) 819 return; 820 821 SectionBookkeeping Section; 822 startSection(Section, wasm::WASM_SEC_EVENT); 823 824 encodeULEB128(Events.size(), W->OS); 825 for (const wasm::WasmEventType &Event : Events) { 826 encodeULEB128(Event.Attribute, W->OS); 827 encodeULEB128(Event.SigIndex, W->OS); 828 } 829 830 endSection(Section); 831 } 832 833 void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) { 834 if (Globals.empty()) 835 return; 836 837 SectionBookkeeping Section; 838 startSection(Section, wasm::WASM_SEC_GLOBAL); 839 840 encodeULEB128(Globals.size(), W->OS); 841 for (const wasm::WasmGlobal &Global : Globals) { 842 encodeULEB128(Global.Type.Type, W->OS); 843 W->OS << char(Global.Type.Mutable); 844 W->OS << char(Global.InitExpr.Opcode); 845 switch (Global.Type.Type) { 846 case wasm::WASM_TYPE_I32: 847 encodeSLEB128(0, W->OS); 848 break; 849 case wasm::WASM_TYPE_I64: 850 encodeSLEB128(0, W->OS); 851 break; 852 case wasm::WASM_TYPE_F32: 853 writeI32(0); 854 break; 855 case wasm::WASM_TYPE_F64: 856 writeI64(0); 857 break; 858 case wasm::WASM_TYPE_EXTERNREF: 859 writeValueType(wasm::ValType::EXTERNREF); 860 break; 861 default: 862 llvm_unreachable("unexpected type"); 863 } 864 W->OS << char(wasm::WASM_OPCODE_END); 865 } 866 867 endSection(Section); 868 } 869 870 void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) { 871 if (Tables.empty()) 872 return; 873 874 SectionBookkeeping Section; 875 startSection(Section, wasm::WASM_SEC_TABLE); 876 877 encodeULEB128(Tables.size(), W->OS); 878 for (const wasm::WasmTable &Table : Tables) { 879 encodeULEB128(Table.Type.ElemType, W->OS); 880 encodeULEB128(Table.Type.Limits.Flags, W->OS); 881 encodeULEB128(Table.Type.Limits.Initial, W->OS); 882 if (Table.Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) 883 encodeULEB128(Table.Type.Limits.Maximum, W->OS); 884 } 885 endSection(Section); 886 } 887 888 void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) { 889 if (Exports.empty()) 890 return; 891 892 SectionBookkeeping Section; 893 startSection(Section, wasm::WASM_SEC_EXPORT); 894 895 encodeULEB128(Exports.size(), W->OS); 896 for (const wasm::WasmExport &Export : Exports) { 897 writeString(Export.Name); 898 W->OS << char(Export.Kind); 899 encodeULEB128(Export.Index, W->OS); 900 } 901 902 endSection(Section); 903 } 904 905 void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { 906 if (TableElems.empty()) 907 return; 908 909 SectionBookkeeping Section; 910 startSection(Section, wasm::WASM_SEC_ELEM); 911 912 encodeULEB128(1, W->OS); // number of "segments" 913 encodeULEB128(0, W->OS); // the table index 914 915 // init expr for starting offset 916 W->OS << char(wasm::WASM_OPCODE_I32_CONST); 917 encodeSLEB128(InitialTableOffset, W->OS); 918 W->OS << char(wasm::WASM_OPCODE_END); 919 920 encodeULEB128(TableElems.size(), W->OS); 921 for (uint32_t Elem : TableElems) 922 encodeULEB128(Elem, W->OS); 923 924 endSection(Section); 925 } 926 927 void WasmObjectWriter::writeDataCountSection() { 928 if (DataSegments.empty()) 929 return; 930 931 SectionBookkeeping Section; 932 startSection(Section, wasm::WASM_SEC_DATACOUNT); 933 encodeULEB128(DataSegments.size(), W->OS); 934 endSection(Section); 935 } 936 937 uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, 938 const MCAsmLayout &Layout, 939 ArrayRef<WasmFunction> Functions) { 940 if (Functions.empty()) 941 return 0; 942 943 SectionBookkeeping Section; 944 startSection(Section, wasm::WASM_SEC_CODE); 945 946 encodeULEB128(Functions.size(), W->OS); 947 948 for (const WasmFunction &Func : Functions) { 949 auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection()); 950 951 int64_t Size = 0; 952 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) 953 report_fatal_error(".size expression must be evaluatable"); 954 955 encodeULEB128(Size, W->OS); 956 FuncSection.setSectionOffset(W->OS.tell() - Section.ContentsOffset); 957 Asm.writeSectionData(W->OS, &FuncSection, Layout); 958 } 959 960 // Apply fixups. 961 applyRelocations(CodeRelocations, Section.ContentsOffset, Layout); 962 963 endSection(Section); 964 return Section.Index; 965 } 966 967 uint32_t WasmObjectWriter::writeDataSection(const MCAsmLayout &Layout) { 968 if (DataSegments.empty()) 969 return 0; 970 971 SectionBookkeeping Section; 972 startSection(Section, wasm::WASM_SEC_DATA); 973 974 encodeULEB128(DataSegments.size(), W->OS); // count 975 976 for (const WasmDataSegment &Segment : DataSegments) { 977 encodeULEB128(Segment.InitFlags, W->OS); // flags 978 if (Segment.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX) 979 encodeULEB128(0, W->OS); // memory index 980 if ((Segment.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) { 981 W->OS << char(is64Bit() ? wasm::WASM_OPCODE_I64_CONST 982 : wasm::WASM_OPCODE_I32_CONST); 983 encodeSLEB128(Segment.Offset, W->OS); // offset 984 W->OS << char(wasm::WASM_OPCODE_END); 985 } 986 encodeULEB128(Segment.Data.size(), W->OS); // size 987 Segment.Section->setSectionOffset(W->OS.tell() - Section.ContentsOffset); 988 W->OS << Segment.Data; // data 989 } 990 991 // Apply fixups. 992 applyRelocations(DataRelocations, Section.ContentsOffset, Layout); 993 994 endSection(Section); 995 return Section.Index; 996 } 997 998 void WasmObjectWriter::writeRelocSection( 999 uint32_t SectionIndex, StringRef Name, 1000 std::vector<WasmRelocationEntry> &Relocs) { 1001 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md 1002 // for descriptions of the reloc sections. 1003 1004 if (Relocs.empty()) 1005 return; 1006 1007 // First, ensure the relocations are sorted in offset order. In general they 1008 // should already be sorted since `recordRelocation` is called in offset 1009 // order, but for the code section we combine many MC sections into single 1010 // wasm section, and this order is determined by the order of Asm.Symbols() 1011 // not the sections order. 1012 llvm::stable_sort( 1013 Relocs, [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) { 1014 return (A.Offset + A.FixupSection->getSectionOffset()) < 1015 (B.Offset + B.FixupSection->getSectionOffset()); 1016 }); 1017 1018 SectionBookkeeping Section; 1019 startCustomSection(Section, std::string("reloc.") + Name.str()); 1020 1021 encodeULEB128(SectionIndex, W->OS); 1022 encodeULEB128(Relocs.size(), W->OS); 1023 for (const WasmRelocationEntry &RelEntry : Relocs) { 1024 uint64_t Offset = 1025 RelEntry.Offset + RelEntry.FixupSection->getSectionOffset(); 1026 uint32_t Index = getRelocationIndexValue(RelEntry); 1027 1028 W->OS << char(RelEntry.Type); 1029 encodeULEB128(Offset, W->OS); 1030 encodeULEB128(Index, W->OS); 1031 if (RelEntry.hasAddend()) 1032 encodeSLEB128(RelEntry.Addend, W->OS); 1033 } 1034 1035 endSection(Section); 1036 } 1037 1038 void WasmObjectWriter::writeCustomRelocSections() { 1039 for (const auto &Sec : CustomSections) { 1040 auto &Relocations = CustomSectionsRelocations[Sec.Section]; 1041 writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations); 1042 } 1043 } 1044 1045 void WasmObjectWriter::writeLinkingMetaDataSection( 1046 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, 1047 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, 1048 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) { 1049 SectionBookkeeping Section; 1050 startCustomSection(Section, "linking"); 1051 encodeULEB128(wasm::WasmMetadataVersion, W->OS); 1052 1053 SectionBookkeeping SubSection; 1054 if (SymbolInfos.size() != 0) { 1055 startSection(SubSection, wasm::WASM_SYMBOL_TABLE); 1056 encodeULEB128(SymbolInfos.size(), W->OS); 1057 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) { 1058 encodeULEB128(Sym.Kind, W->OS); 1059 encodeULEB128(Sym.Flags, W->OS); 1060 switch (Sym.Kind) { 1061 case wasm::WASM_SYMBOL_TYPE_FUNCTION: 1062 case wasm::WASM_SYMBOL_TYPE_GLOBAL: 1063 case wasm::WASM_SYMBOL_TYPE_EVENT: 1064 case wasm::WASM_SYMBOL_TYPE_TABLE: 1065 encodeULEB128(Sym.ElementIndex, W->OS); 1066 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 || 1067 (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) 1068 writeString(Sym.Name); 1069 break; 1070 case wasm::WASM_SYMBOL_TYPE_DATA: 1071 writeString(Sym.Name); 1072 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { 1073 encodeULEB128(Sym.DataRef.Segment, W->OS); 1074 encodeULEB128(Sym.DataRef.Offset, W->OS); 1075 encodeULEB128(Sym.DataRef.Size, W->OS); 1076 } 1077 break; 1078 case wasm::WASM_SYMBOL_TYPE_SECTION: { 1079 const uint32_t SectionIndex = 1080 CustomSections[Sym.ElementIndex].OutputIndex; 1081 encodeULEB128(SectionIndex, W->OS); 1082 break; 1083 } 1084 default: 1085 llvm_unreachable("unexpected kind"); 1086 } 1087 } 1088 endSection(SubSection); 1089 } 1090 1091 if (DataSegments.size()) { 1092 startSection(SubSection, wasm::WASM_SEGMENT_INFO); 1093 encodeULEB128(DataSegments.size(), W->OS); 1094 for (const WasmDataSegment &Segment : DataSegments) { 1095 writeString(Segment.Name); 1096 encodeULEB128(Segment.Alignment, W->OS); 1097 encodeULEB128(Segment.LinkerFlags, W->OS); 1098 } 1099 endSection(SubSection); 1100 } 1101 1102 if (!InitFuncs.empty()) { 1103 startSection(SubSection, wasm::WASM_INIT_FUNCS); 1104 encodeULEB128(InitFuncs.size(), W->OS); 1105 for (auto &StartFunc : InitFuncs) { 1106 encodeULEB128(StartFunc.first, W->OS); // priority 1107 encodeULEB128(StartFunc.second, W->OS); // function index 1108 } 1109 endSection(SubSection); 1110 } 1111 1112 if (Comdats.size()) { 1113 startSection(SubSection, wasm::WASM_COMDAT_INFO); 1114 encodeULEB128(Comdats.size(), W->OS); 1115 for (const auto &C : Comdats) { 1116 writeString(C.first); 1117 encodeULEB128(0, W->OS); // flags for future use 1118 encodeULEB128(C.second.size(), W->OS); 1119 for (const WasmComdatEntry &Entry : C.second) { 1120 encodeULEB128(Entry.Kind, W->OS); 1121 encodeULEB128(Entry.Index, W->OS); 1122 } 1123 } 1124 endSection(SubSection); 1125 } 1126 1127 endSection(Section); 1128 } 1129 1130 void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection, 1131 const MCAssembler &Asm, 1132 const MCAsmLayout &Layout) { 1133 SectionBookkeeping Section; 1134 auto *Sec = CustomSection.Section; 1135 startCustomSection(Section, CustomSection.Name); 1136 1137 Sec->setSectionOffset(W->OS.tell() - Section.ContentsOffset); 1138 Asm.writeSectionData(W->OS, Sec, Layout); 1139 1140 CustomSection.OutputContentsOffset = Section.ContentsOffset; 1141 CustomSection.OutputIndex = Section.Index; 1142 1143 endSection(Section); 1144 1145 // Apply fixups. 1146 auto &Relocations = CustomSectionsRelocations[CustomSection.Section]; 1147 applyRelocations(Relocations, CustomSection.OutputContentsOffset, Layout); 1148 } 1149 1150 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) { 1151 assert(Symbol.isFunction()); 1152 assert(TypeIndices.count(&Symbol)); 1153 return TypeIndices[&Symbol]; 1154 } 1155 1156 uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) { 1157 assert(Symbol.isEvent()); 1158 assert(TypeIndices.count(&Symbol)); 1159 return TypeIndices[&Symbol]; 1160 } 1161 1162 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { 1163 assert(Symbol.isFunction()); 1164 1165 wasm::WasmSignature S; 1166 1167 if (auto *Sig = Symbol.getSignature()) { 1168 S.Returns = Sig->Returns; 1169 S.Params = Sig->Params; 1170 } 1171 1172 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size())); 1173 if (Pair.second) 1174 Signatures.push_back(S); 1175 TypeIndices[&Symbol] = Pair.first->second; 1176 1177 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol 1178 << " new:" << Pair.second << "\n"); 1179 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); 1180 } 1181 1182 void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) { 1183 assert(Symbol.isEvent()); 1184 1185 // TODO Currently we don't generate imported exceptions, but if we do, we 1186 // should have a way of infering types of imported exceptions. 1187 wasm::WasmSignature S; 1188 if (auto *Sig = Symbol.getSignature()) { 1189 S.Returns = Sig->Returns; 1190 S.Params = Sig->Params; 1191 } 1192 1193 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size())); 1194 if (Pair.second) 1195 Signatures.push_back(S); 1196 TypeIndices[&Symbol] = Pair.first->second; 1197 1198 LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second 1199 << "\n"); 1200 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); 1201 } 1202 1203 static bool isInSymtab(const MCSymbolWasm &Sym) { 1204 if (Sym.isUsedInReloc() || Sym.isUsedInInitArray()) 1205 return true; 1206 1207 if (Sym.isComdat() && !Sym.isDefined()) 1208 return false; 1209 1210 if (Sym.isTemporary()) 1211 return false; 1212 1213 if (Sym.isSection()) 1214 return false; 1215 1216 if (Sym.omitFromLinkingSection()) 1217 return false; 1218 1219 return true; 1220 } 1221 1222 void WasmObjectWriter::prepareImports( 1223 SmallVectorImpl<wasm::WasmImport> &Imports, MCAssembler &Asm, 1224 const MCAsmLayout &Layout) { 1225 // For now, always emit the memory import, since loads and stores are not 1226 // valid without it. In the future, we could perhaps be more clever and omit 1227 // it if there are no loads or stores. 1228 wasm::WasmImport MemImport; 1229 MemImport.Module = "env"; 1230 MemImport.Field = "__linear_memory"; 1231 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; 1232 MemImport.Memory.Flags = is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64 1233 : wasm::WASM_LIMITS_FLAG_NONE; 1234 Imports.push_back(MemImport); 1235 1236 // Populate SignatureIndices, and Imports and WasmIndices for undefined 1237 // symbols. This must be done before populating WasmIndices for defined 1238 // symbols. 1239 for (const MCSymbol &S : Asm.symbols()) { 1240 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1241 1242 // Register types for all functions, including those with private linkage 1243 // (because wasm always needs a type signature). 1244 if (WS.isFunction()) { 1245 const auto *BS = Layout.getBaseSymbol(S); 1246 if (!BS) 1247 report_fatal_error(Twine(S.getName()) + 1248 ": absolute addressing not supported!"); 1249 registerFunctionType(*cast<MCSymbolWasm>(BS)); 1250 } 1251 1252 if (WS.isEvent()) 1253 registerEventType(WS); 1254 1255 if (WS.isTemporary()) 1256 continue; 1257 1258 // If the symbol is not defined in this translation unit, import it. 1259 if (!WS.isDefined() && !WS.isComdat()) { 1260 if (WS.isFunction()) { 1261 wasm::WasmImport Import; 1262 Import.Module = WS.getImportModule(); 1263 Import.Field = WS.getImportName(); 1264 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; 1265 Import.SigIndex = getFunctionType(WS); 1266 Imports.push_back(Import); 1267 assert(WasmIndices.count(&WS) == 0); 1268 WasmIndices[&WS] = NumFunctionImports++; 1269 } else if (WS.isGlobal()) { 1270 if (WS.isWeak()) 1271 report_fatal_error("undefined global symbol cannot be weak"); 1272 1273 wasm::WasmImport Import; 1274 Import.Field = WS.getImportName(); 1275 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; 1276 Import.Module = WS.getImportModule(); 1277 Import.Global = WS.getGlobalType(); 1278 Imports.push_back(Import); 1279 assert(WasmIndices.count(&WS) == 0); 1280 WasmIndices[&WS] = NumGlobalImports++; 1281 } else if (WS.isEvent()) { 1282 if (WS.isWeak()) 1283 report_fatal_error("undefined event symbol cannot be weak"); 1284 1285 wasm::WasmImport Import; 1286 Import.Module = WS.getImportModule(); 1287 Import.Field = WS.getImportName(); 1288 Import.Kind = wasm::WASM_EXTERNAL_EVENT; 1289 Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; 1290 Import.Event.SigIndex = getEventType(WS); 1291 Imports.push_back(Import); 1292 assert(WasmIndices.count(&WS) == 0); 1293 WasmIndices[&WS] = NumEventImports++; 1294 } else if (WS.isTable()) { 1295 if (WS.isWeak()) 1296 report_fatal_error("undefined table symbol cannot be weak"); 1297 1298 wasm::WasmImport Import; 1299 Import.Module = WS.getImportModule(); 1300 Import.Field = WS.getImportName(); 1301 Import.Kind = wasm::WASM_EXTERNAL_TABLE; 1302 wasm::ValType ElemType = WS.getTableType(); 1303 Import.Table.ElemType = uint8_t(ElemType); 1304 // FIXME: Extend table type to include limits? For now we don't specify 1305 // a min or max which does not place any restrictions on the size of the 1306 // imported table. 1307 Import.Table.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; 1308 Imports.push_back(Import); 1309 assert(WasmIndices.count(&WS) == 0); 1310 WasmIndices[&WS] = NumTableImports++; 1311 } 1312 } 1313 } 1314 1315 // Add imports for GOT globals 1316 for (const MCSymbol &S : Asm.symbols()) { 1317 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1318 if (WS.isUsedInGOT()) { 1319 wasm::WasmImport Import; 1320 if (WS.isFunction()) 1321 Import.Module = "GOT.func"; 1322 else 1323 Import.Module = "GOT.mem"; 1324 Import.Field = WS.getName(); 1325 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; 1326 Import.Global = {wasm::WASM_TYPE_I32, true}; 1327 Imports.push_back(Import); 1328 assert(GOTIndices.count(&WS) == 0); 1329 GOTIndices[&WS] = NumGlobalImports++; 1330 } 1331 } 1332 } 1333 1334 uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, 1335 const MCAsmLayout &Layout) { 1336 support::endian::Writer MainWriter(*OS, support::little); 1337 W = &MainWriter; 1338 if (IsSplitDwarf) { 1339 uint64_t TotalSize = writeOneObject(Asm, Layout, DwoMode::NonDwoOnly); 1340 assert(DwoOS); 1341 support::endian::Writer DwoWriter(*DwoOS, support::little); 1342 W = &DwoWriter; 1343 return TotalSize + writeOneObject(Asm, Layout, DwoMode::DwoOnly); 1344 } else { 1345 return writeOneObject(Asm, Layout, DwoMode::AllSections); 1346 } 1347 } 1348 1349 uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm, 1350 const MCAsmLayout &Layout, 1351 DwoMode Mode) { 1352 uint64_t StartOffset = W->OS.tell(); 1353 SectionCount = 0; 1354 CustomSections.clear(); 1355 1356 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); 1357 1358 // Collect information from the available symbols. 1359 SmallVector<WasmFunction, 4> Functions; 1360 SmallVector<uint32_t, 4> TableElems; 1361 SmallVector<wasm::WasmImport, 4> Imports; 1362 SmallVector<wasm::WasmExport, 4> Exports; 1363 SmallVector<wasm::WasmEventType, 1> Events; 1364 SmallVector<wasm::WasmGlobal, 1> Globals; 1365 SmallVector<wasm::WasmTable, 1> Tables; 1366 SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; 1367 SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; 1368 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; 1369 uint64_t DataSize = 0; 1370 if (Mode != DwoMode::DwoOnly) { 1371 prepareImports(Imports, Asm, Layout); 1372 } 1373 1374 // Populate DataSegments and CustomSections, which must be done before 1375 // populating DataLocations. 1376 for (MCSection &Sec : Asm) { 1377 auto &Section = static_cast<MCSectionWasm &>(Sec); 1378 StringRef SectionName = Section.getName(); 1379 1380 if (Mode == DwoMode::NonDwoOnly && isDwoSection(Sec)) 1381 continue; 1382 if (Mode == DwoMode::DwoOnly && !isDwoSection(Sec)) 1383 continue; 1384 1385 LLVM_DEBUG(dbgs() << "Processing Section " << SectionName << " group " 1386 << Section.getGroup() << "\n";); 1387 1388 // .init_array sections are handled specially elsewhere. 1389 if (SectionName.startswith(".init_array")) 1390 continue; 1391 1392 // Code is handled separately 1393 if (Section.getKind().isText()) 1394 continue; 1395 1396 if (Section.isWasmData()) { 1397 uint32_t SegmentIndex = DataSegments.size(); 1398 DataSize = alignTo(DataSize, Section.getAlignment()); 1399 DataSegments.emplace_back(); 1400 WasmDataSegment &Segment = DataSegments.back(); 1401 Segment.Name = SectionName; 1402 Segment.InitFlags = Section.getPassive() 1403 ? (uint32_t)wasm::WASM_DATA_SEGMENT_IS_PASSIVE 1404 : 0; 1405 Segment.Offset = DataSize; 1406 Segment.Section = &Section; 1407 addData(Segment.Data, Section); 1408 Segment.Alignment = Log2_32(Section.getAlignment()); 1409 Segment.LinkerFlags = 0; 1410 DataSize += Segment.Data.size(); 1411 Section.setSegmentIndex(SegmentIndex); 1412 1413 if (const MCSymbolWasm *C = Section.getGroup()) { 1414 Comdats[C->getName()].emplace_back( 1415 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex}); 1416 } 1417 } else { 1418 // Create custom sections 1419 assert(Sec.getKind().isMetadata()); 1420 1421 StringRef Name = SectionName; 1422 1423 // For user-defined custom sections, strip the prefix 1424 if (Name.startswith(".custom_section.")) 1425 Name = Name.substr(strlen(".custom_section.")); 1426 1427 MCSymbol *Begin = Sec.getBeginSymbol(); 1428 if (Begin) { 1429 assert(WasmIndices.count(cast<MCSymbolWasm>(Begin)) == 0); 1430 WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size(); 1431 } 1432 1433 // Separate out the producers and target features sections 1434 if (Name == "producers") { 1435 ProducersSection = std::make_unique<WasmCustomSection>(Name, &Section); 1436 continue; 1437 } 1438 if (Name == "target_features") { 1439 TargetFeaturesSection = 1440 std::make_unique<WasmCustomSection>(Name, &Section); 1441 continue; 1442 } 1443 1444 // Custom sections can also belong to COMDAT groups. In this case the 1445 // decriptor's "index" field is the section index (in the final object 1446 // file), but that is not known until after layout, so it must be fixed up 1447 // later 1448 if (const MCSymbolWasm *C = Section.getGroup()) { 1449 Comdats[C->getName()].emplace_back( 1450 WasmComdatEntry{wasm::WASM_COMDAT_SECTION, 1451 static_cast<uint32_t>(CustomSections.size())}); 1452 } 1453 1454 CustomSections.emplace_back(Name, &Section); 1455 } 1456 } 1457 1458 if (Mode != DwoMode::DwoOnly) { 1459 // Populate WasmIndices and DataLocations for defined symbols. 1460 for (const MCSymbol &S : Asm.symbols()) { 1461 // Ignore unnamed temporary symbols, which aren't ever exported, imported, 1462 // or used in relocations. 1463 if (S.isTemporary() && S.getName().empty()) 1464 continue; 1465 1466 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1467 LLVM_DEBUG(dbgs() 1468 << "MCSymbol: " 1469 << toString(WS.getType().getValueOr(wasm::WASM_SYMBOL_TYPE_DATA)) 1470 << " '" << S << "'" 1471 << " isDefined=" << S.isDefined() << " isExternal=" 1472 << S.isExternal() << " isTemporary=" << S.isTemporary() 1473 << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden() 1474 << " isVariable=" << WS.isVariable() << "\n"); 1475 1476 if (WS.isVariable()) 1477 continue; 1478 if (WS.isComdat() && !WS.isDefined()) 1479 continue; 1480 1481 if (WS.isFunction()) { 1482 unsigned Index; 1483 if (WS.isDefined()) { 1484 if (WS.getOffset() != 0) 1485 report_fatal_error( 1486 "function sections must contain one function each"); 1487 1488 if (WS.getSize() == nullptr) 1489 report_fatal_error( 1490 "function symbols must have a size set with .size"); 1491 1492 // A definition. Write out the function body. 1493 Index = NumFunctionImports + Functions.size(); 1494 WasmFunction Func; 1495 Func.SigIndex = getFunctionType(WS); 1496 Func.Sym = &WS; 1497 assert(WasmIndices.count(&WS) == 0); 1498 WasmIndices[&WS] = Index; 1499 Functions.push_back(Func); 1500 1501 auto &Section = static_cast<MCSectionWasm &>(WS.getSection()); 1502 if (const MCSymbolWasm *C = Section.getGroup()) { 1503 Comdats[C->getName()].emplace_back( 1504 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); 1505 } 1506 1507 if (WS.hasExportName()) { 1508 wasm::WasmExport Export; 1509 Export.Name = WS.getExportName(); 1510 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; 1511 Export.Index = Index; 1512 Exports.push_back(Export); 1513 } 1514 } else { 1515 // An import; the index was assigned above. 1516 Index = WasmIndices.find(&WS)->second; 1517 } 1518 1519 LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); 1520 1521 } else if (WS.isData()) { 1522 if (!isInSymtab(WS)) 1523 continue; 1524 1525 if (!WS.isDefined()) { 1526 LLVM_DEBUG(dbgs() << " -> segment index: -1" 1527 << "\n"); 1528 continue; 1529 } 1530 1531 if (!WS.getSize()) 1532 report_fatal_error("data symbols must have a size set with .size: " + 1533 WS.getName()); 1534 1535 int64_t Size = 0; 1536 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) 1537 report_fatal_error(".size expression must be evaluatable"); 1538 1539 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); 1540 if (!DataSection.isWasmData()) 1541 report_fatal_error("data symbols must live in a data section: " + 1542 WS.getName()); 1543 1544 // For each data symbol, export it in the symtab as a reference to the 1545 // corresponding Wasm data segment. 1546 wasm::WasmDataReference Ref = wasm::WasmDataReference{ 1547 DataSection.getSegmentIndex(), Layout.getSymbolOffset(WS), 1548 static_cast<uint64_t>(Size)}; 1549 assert(DataLocations.count(&WS) == 0); 1550 DataLocations[&WS] = Ref; 1551 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); 1552 1553 } else if (WS.isGlobal()) { 1554 // A "true" Wasm global (currently just __stack_pointer) 1555 if (WS.isDefined()) { 1556 wasm::WasmGlobal Global; 1557 Global.Type = WS.getGlobalType(); 1558 Global.Index = NumGlobalImports + Globals.size(); 1559 switch (Global.Type.Type) { 1560 case wasm::WASM_TYPE_I32: 1561 Global.InitExpr.Opcode = wasm::WASM_OPCODE_I32_CONST; 1562 break; 1563 case wasm::WASM_TYPE_I64: 1564 Global.InitExpr.Opcode = wasm::WASM_OPCODE_I64_CONST; 1565 break; 1566 case wasm::WASM_TYPE_F32: 1567 Global.InitExpr.Opcode = wasm::WASM_OPCODE_F32_CONST; 1568 break; 1569 case wasm::WASM_TYPE_F64: 1570 Global.InitExpr.Opcode = wasm::WASM_OPCODE_F64_CONST; 1571 break; 1572 case wasm::WASM_TYPE_EXTERNREF: 1573 Global.InitExpr.Opcode = wasm::WASM_OPCODE_REF_NULL; 1574 break; 1575 default: 1576 llvm_unreachable("unexpected type"); 1577 } 1578 assert(WasmIndices.count(&WS) == 0); 1579 WasmIndices[&WS] = Global.Index; 1580 Globals.push_back(Global); 1581 } else { 1582 // An import; the index was assigned above 1583 LLVM_DEBUG(dbgs() << " -> global index: " 1584 << WasmIndices.find(&WS)->second << "\n"); 1585 } 1586 } else if (WS.isTable()) { 1587 if (WS.isDefined()) { 1588 wasm::WasmTable Table; 1589 Table.Index = NumTableImports + Tables.size(); 1590 Table.Type.ElemType = static_cast<uint8_t>(WS.getTableType()); 1591 // FIXME: Work on custom limits is ongoing 1592 Table.Type.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; 1593 assert(WasmIndices.count(&WS) == 0); 1594 WasmIndices[&WS] = Table.Index; 1595 Tables.push_back(Table); 1596 } 1597 LLVM_DEBUG(dbgs() << " -> table index: " 1598 << WasmIndices.find(&WS)->second << "\n"); 1599 } else if (WS.isEvent()) { 1600 // C++ exception symbol (__cpp_exception) 1601 unsigned Index; 1602 if (WS.isDefined()) { 1603 Index = NumEventImports + Events.size(); 1604 wasm::WasmEventType Event; 1605 Event.SigIndex = getEventType(WS); 1606 Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; 1607 assert(WasmIndices.count(&WS) == 0); 1608 WasmIndices[&WS] = Index; 1609 Events.push_back(Event); 1610 } else { 1611 // An import; the index was assigned above. 1612 assert(WasmIndices.count(&WS) > 0); 1613 } 1614 LLVM_DEBUG(dbgs() << " -> event index: " 1615 << WasmIndices.find(&WS)->second << "\n"); 1616 1617 } else { 1618 assert(WS.isSection()); 1619 } 1620 } 1621 1622 // Populate WasmIndices and DataLocations for aliased symbols. We need to 1623 // process these in a separate pass because we need to have processed the 1624 // target of the alias before the alias itself and the symbols are not 1625 // necessarily ordered in this way. 1626 for (const MCSymbol &S : Asm.symbols()) { 1627 if (!S.isVariable()) 1628 continue; 1629 1630 assert(S.isDefined()); 1631 1632 const auto *BS = Layout.getBaseSymbol(S); 1633 if (!BS) 1634 report_fatal_error(Twine(S.getName()) + 1635 ": absolute addressing not supported!"); 1636 const MCSymbolWasm *Base = cast<MCSymbolWasm>(BS); 1637 1638 // Find the target symbol of this weak alias and export that index 1639 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1640 LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *Base 1641 << "'\n"); 1642 1643 if (Base->isFunction()) { 1644 assert(WasmIndices.count(Base) > 0); 1645 uint32_t WasmIndex = WasmIndices.find(Base)->second; 1646 assert(WasmIndices.count(&WS) == 0); 1647 WasmIndices[&WS] = WasmIndex; 1648 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); 1649 } else if (Base->isData()) { 1650 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); 1651 uint64_t Offset = Layout.getSymbolOffset(S); 1652 int64_t Size = 0; 1653 // For data symbol alias we use the size of the base symbol as the 1654 // size of the alias. When an offset from the base is involved this 1655 // can result in a offset + size goes past the end of the data section 1656 // which out object format doesn't support. So we must clamp it. 1657 if (!Base->getSize()->evaluateAsAbsolute(Size, Layout)) 1658 report_fatal_error(".size expression must be evaluatable"); 1659 const WasmDataSegment &Segment = 1660 DataSegments[DataSection.getSegmentIndex()]; 1661 Size = 1662 std::min(static_cast<uint64_t>(Size), Segment.Data.size() - Offset); 1663 wasm::WasmDataReference Ref = wasm::WasmDataReference{ 1664 DataSection.getSegmentIndex(), 1665 static_cast<uint32_t>(Layout.getSymbolOffset(S)), 1666 static_cast<uint32_t>(Size)}; 1667 DataLocations[&WS] = Ref; 1668 LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); 1669 } else { 1670 report_fatal_error("don't yet support global/event aliases"); 1671 } 1672 } 1673 } 1674 1675 // Finally, populate the symbol table itself, in its "natural" order. 1676 for (const MCSymbol &S : Asm.symbols()) { 1677 const auto &WS = static_cast<const MCSymbolWasm &>(S); 1678 if (!isInSymtab(WS)) { 1679 WS.setIndex(InvalidIndex); 1680 continue; 1681 } 1682 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n"); 1683 1684 uint32_t Flags = 0; 1685 if (WS.isWeak()) 1686 Flags |= wasm::WASM_SYMBOL_BINDING_WEAK; 1687 if (WS.isHidden()) 1688 Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN; 1689 if (!WS.isExternal() && WS.isDefined()) 1690 Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; 1691 if (WS.isUndefined()) 1692 Flags |= wasm::WASM_SYMBOL_UNDEFINED; 1693 if (WS.isNoStrip()) { 1694 Flags |= wasm::WASM_SYMBOL_NO_STRIP; 1695 if (isEmscripten()) { 1696 Flags |= wasm::WASM_SYMBOL_EXPORTED; 1697 } 1698 } 1699 if (WS.hasImportName()) 1700 Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME; 1701 if (WS.hasExportName()) 1702 Flags |= wasm::WASM_SYMBOL_EXPORTED; 1703 1704 wasm::WasmSymbolInfo Info; 1705 Info.Name = WS.getName(); 1706 Info.Kind = WS.getType().getValueOr(wasm::WASM_SYMBOL_TYPE_DATA); 1707 Info.Flags = Flags; 1708 if (!WS.isData()) { 1709 assert(WasmIndices.count(&WS) > 0); 1710 Info.ElementIndex = WasmIndices.find(&WS)->second; 1711 } else if (WS.isDefined()) { 1712 assert(DataLocations.count(&WS) > 0); 1713 Info.DataRef = DataLocations.find(&WS)->second; 1714 } 1715 WS.setIndex(SymbolInfos.size()); 1716 SymbolInfos.emplace_back(Info); 1717 } 1718 1719 { 1720 auto HandleReloc = [&](const WasmRelocationEntry &Rel) { 1721 // Functions referenced by a relocation need to put in the table. This is 1722 // purely to make the object file's provisional values readable, and is 1723 // ignored by the linker, which re-calculates the relocations itself. 1724 if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 && 1725 Rel.Type != wasm::R_WASM_TABLE_INDEX_I64 && 1726 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB && 1727 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB64 && 1728 Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB) 1729 return; 1730 assert(Rel.Symbol->isFunction()); 1731 const MCSymbolWasm *Base = 1732 cast<MCSymbolWasm>(Layout.getBaseSymbol(*Rel.Symbol)); 1733 uint32_t FunctionIndex = WasmIndices.find(Base)->second; 1734 uint32_t TableIndex = TableElems.size() + InitialTableOffset; 1735 if (TableIndices.try_emplace(Base, TableIndex).second) { 1736 LLVM_DEBUG(dbgs() << " -> adding " << Base->getName() 1737 << " to table: " << TableIndex << "\n"); 1738 TableElems.push_back(FunctionIndex); 1739 registerFunctionType(*Base); 1740 } 1741 }; 1742 1743 for (const WasmRelocationEntry &RelEntry : CodeRelocations) 1744 HandleReloc(RelEntry); 1745 for (const WasmRelocationEntry &RelEntry : DataRelocations) 1746 HandleReloc(RelEntry); 1747 } 1748 1749 // Translate .init_array section contents into start functions. 1750 for (const MCSection &S : Asm) { 1751 const auto &WS = static_cast<const MCSectionWasm &>(S); 1752 if (WS.getName().startswith(".fini_array")) 1753 report_fatal_error(".fini_array sections are unsupported"); 1754 if (!WS.getName().startswith(".init_array")) 1755 continue; 1756 if (WS.getFragmentList().empty()) 1757 continue; 1758 1759 // init_array is expected to contain a single non-empty data fragment 1760 if (WS.getFragmentList().size() != 3) 1761 report_fatal_error("only one .init_array section fragment supported"); 1762 1763 auto IT = WS.begin(); 1764 const MCFragment &EmptyFrag = *IT; 1765 if (EmptyFrag.getKind() != MCFragment::FT_Data) 1766 report_fatal_error(".init_array section should be aligned"); 1767 1768 IT = std::next(IT); 1769 const MCFragment &AlignFrag = *IT; 1770 if (AlignFrag.getKind() != MCFragment::FT_Align) 1771 report_fatal_error(".init_array section should be aligned"); 1772 if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4)) 1773 report_fatal_error(".init_array section should be aligned for pointers"); 1774 1775 const MCFragment &Frag = *std::next(IT); 1776 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) 1777 report_fatal_error("only data supported in .init_array section"); 1778 1779 uint16_t Priority = UINT16_MAX; 1780 unsigned PrefixLength = strlen(".init_array"); 1781 if (WS.getName().size() > PrefixLength) { 1782 if (WS.getName()[PrefixLength] != '.') 1783 report_fatal_error( 1784 ".init_array section priority should start with '.'"); 1785 if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority)) 1786 report_fatal_error("invalid .init_array section priority"); 1787 } 1788 const auto &DataFrag = cast<MCDataFragment>(Frag); 1789 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 1790 for (const uint8_t * 1791 P = (const uint8_t *)Contents.data(), 1792 *End = (const uint8_t *)Contents.data() + Contents.size(); 1793 P != End; ++P) { 1794 if (*P != 0) 1795 report_fatal_error("non-symbolic data in .init_array section"); 1796 } 1797 for (const MCFixup &Fixup : DataFrag.getFixups()) { 1798 assert(Fixup.getKind() == 1799 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false)); 1800 const MCExpr *Expr = Fixup.getValue(); 1801 auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr); 1802 if (!SymRef) 1803 report_fatal_error("fixups in .init_array should be symbol references"); 1804 const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol()); 1805 if (TargetSym.getIndex() == InvalidIndex) 1806 report_fatal_error("symbols in .init_array should exist in symtab"); 1807 if (!TargetSym.isFunction()) 1808 report_fatal_error("symbols in .init_array should be for functions"); 1809 InitFuncs.push_back( 1810 std::make_pair(Priority, TargetSym.getIndex())); 1811 } 1812 } 1813 1814 // Write out the Wasm header. 1815 writeHeader(Asm); 1816 1817 uint32_t CodeSectionIndex, DataSectionIndex; 1818 if (Mode != DwoMode::DwoOnly) { 1819 writeTypeSection(Signatures); 1820 writeImportSection(Imports, DataSize, TableElems.size()); 1821 writeFunctionSection(Functions); 1822 writeTableSection(Tables); 1823 // Skip the "memory" section; we import the memory instead. 1824 writeEventSection(Events); 1825 writeGlobalSection(Globals); 1826 writeExportSection(Exports); 1827 writeElemSection(TableElems); 1828 writeDataCountSection(); 1829 1830 CodeSectionIndex = writeCodeSection(Asm, Layout, Functions); 1831 DataSectionIndex = writeDataSection(Layout); 1832 } 1833 1834 // The Sections in the COMDAT list have placeholder indices (their index among 1835 // custom sections, rather than among all sections). Fix them up here. 1836 for (auto &Group : Comdats) { 1837 for (auto &Entry : Group.second) { 1838 if (Entry.Kind == wasm::WASM_COMDAT_SECTION) { 1839 Entry.Index += SectionCount; 1840 } 1841 } 1842 } 1843 for (auto &CustomSection : CustomSections) 1844 writeCustomSection(CustomSection, Asm, Layout); 1845 1846 if (Mode != DwoMode::DwoOnly) { 1847 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); 1848 1849 writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations); 1850 writeRelocSection(DataSectionIndex, "DATA", DataRelocations); 1851 } 1852 writeCustomRelocSections(); 1853 if (ProducersSection) 1854 writeCustomSection(*ProducersSection, Asm, Layout); 1855 if (TargetFeaturesSection) 1856 writeCustomSection(*TargetFeaturesSection, Asm, Layout); 1857 1858 // TODO: Translate the .comment section to the output. 1859 return W->OS.tell() - StartOffset; 1860 } 1861 1862 std::unique_ptr<MCObjectWriter> 1863 llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, 1864 raw_pwrite_stream &OS) { 1865 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS); 1866 } 1867 1868 std::unique_ptr<MCObjectWriter> 1869 llvm::createWasmDwoObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, 1870 raw_pwrite_stream &OS, 1871 raw_pwrite_stream &DwoOS) { 1872 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS, DwoOS); 1873 } 1874