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