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