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/MC/MCAsmBackend.h" 17 #include "llvm/MC/MCAsmInfo.h" 18 #include "llvm/MC/MCAsmLayout.h" 19 #include "llvm/MC/MCAssembler.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCExpr.h" 22 #include "llvm/MC/MCFixupKindInfo.h" 23 #include "llvm/MC/MCObjectFileInfo.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 "llvm/Support/Wasm.h" 35 #include <vector> 36 37 using namespace llvm; 38 39 #undef DEBUG_TYPE 40 #define DEBUG_TYPE "reloc-info" 41 42 namespace { 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 contents of the section starts (after the header). 50 uint64_t ContentsOffset; 51 }; 52 53 // This record records information about a call_indirect which needs its 54 // type index fixed up once we've computed type indices. 55 struct TypeIndexFixup { 56 uint64_t Offset; 57 const MCSymbolWasm *Symbol; 58 const MCSectionWasm *FixupSection; 59 TypeIndexFixup(uint64_t O, const MCSymbolWasm *S, MCSectionWasm *F) 60 : Offset(O), Symbol(S), FixupSection(F) {} 61 }; 62 63 class WasmObjectWriter : public MCObjectWriter { 64 /// Helper struct for containing some precomputed information on symbols. 65 struct WasmSymbolData { 66 const MCSymbolWasm *Symbol; 67 StringRef Name; 68 69 // Support lexicographic sorting. 70 bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; } 71 }; 72 73 /// The target specific Wasm writer instance. 74 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter; 75 76 // Relocations for fixing up references in the code section. 77 std::vector<WasmRelocationEntry> CodeRelocations; 78 79 // Relocations for fixing up references in the data section. 80 std::vector<WasmRelocationEntry> DataRelocations; 81 82 // Fixups for call_indirect type indices. 83 std::vector<TypeIndexFixup> TypeIndexFixups; 84 85 // Index values to use for fixing up call_indirect type indices. 86 std::vector<uint32_t> TypeIndexFixupTypes; 87 88 // TargetObjectWriter wrappers. 89 bool is64Bit() const { return TargetObjectWriter->is64Bit(); } 90 unsigned getRelocType(MCContext &Ctx, const MCValue &Target, 91 const MCFixup &Fixup, bool IsPCRel) const { 92 return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); 93 } 94 95 void startSection(SectionBookkeeping &Section, unsigned SectionId, 96 const char *Name = nullptr); 97 void endSection(SectionBookkeeping &Section); 98 99 public: 100 WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS) 101 : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {} 102 103 private: 104 void reset() override { 105 MCObjectWriter::reset(); 106 } 107 108 ~WasmObjectWriter() override; 109 110 void writeHeader(const MCAssembler &Asm); 111 112 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 113 const MCFragment *Fragment, const MCFixup &Fixup, 114 MCValue Target, bool &IsPCRel, 115 uint64_t &FixedValue) override; 116 117 void executePostLayoutBinding(MCAssembler &Asm, 118 const MCAsmLayout &Layout) override; 119 120 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; 121 }; 122 } // end anonymous namespace 123 124 WasmObjectWriter::~WasmObjectWriter() {} 125 126 // Return the padding size to write a 32-bit value into a 5-byte ULEB128. 127 static unsigned PaddingFor5ByteULEB128(uint32_t X) { 128 return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u); 129 } 130 131 // Return the padding size to write a 32-bit value into a 5-byte SLEB128. 132 static unsigned PaddingFor5ByteSLEB128(int32_t X) { 133 return 5 - getSLEB128Size(X); 134 } 135 136 // Write out a section header and a patchable section size field. 137 void WasmObjectWriter::startSection(SectionBookkeeping &Section, 138 unsigned SectionId, 139 const char *Name) { 140 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && 141 "Only custom sections can have names"); 142 143 write8(SectionId); 144 145 Section.SizeOffset = getStream().tell(); 146 147 // The section size. We don't know the size yet, so reserve enough space 148 // for any 32-bit value; we'll patch it later. 149 encodeULEB128(UINT32_MAX, getStream()); 150 151 // The position where the section starts, for measuring its size. 152 Section.ContentsOffset = getStream().tell(); 153 154 // Custom sections in wasm also have a string identifier. 155 if (SectionId == wasm::WASM_SEC_CUSTOM) { 156 encodeULEB128(strlen(Name), getStream()); 157 writeBytes(Name); 158 } 159 } 160 161 // Now that the section is complete and we know how big it is, patch up the 162 // section size field at the start of the section. 163 void WasmObjectWriter::endSection(SectionBookkeeping &Section) { 164 uint64_t Size = getStream().tell() - Section.ContentsOffset; 165 if (uint32_t(Size) != Size) 166 report_fatal_error("section size does not fit in a uint32_t"); 167 168 unsigned Padding = PaddingFor5ByteULEB128(Size); 169 170 // Write the final section size to the payload_len field, which follows 171 // the section id byte. 172 uint8_t Buffer[16]; 173 unsigned SizeLen = encodeULEB128(Size, Buffer, Padding); 174 assert(SizeLen == 5); 175 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); 176 } 177 178 // Emit the Wasm header. 179 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { 180 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic))); 181 writeLE32(wasm::WasmVersion); 182 } 183 184 void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, 185 const MCAsmLayout &Layout) { 186 } 187 188 void WasmObjectWriter::recordRelocation(MCAssembler &Asm, 189 const MCAsmLayout &Layout, 190 const MCFragment *Fragment, 191 const MCFixup &Fixup, MCValue Target, 192 bool &IsPCRel, uint64_t &FixedValue) { 193 MCSectionWasm &FixupSection = cast<MCSectionWasm>(*Fragment->getParent()); 194 uint64_t C = Target.getConstant(); 195 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 196 MCContext &Ctx = Asm.getContext(); 197 198 if (const MCSymbolRefExpr *RefB = Target.getSymB()) { 199 assert(RefB->getKind() == MCSymbolRefExpr::VK_None && 200 "Should not have constructed this"); 201 202 // Let A, B and C being the components of Target and R be the location of 203 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). 204 // If it is pcrel, we want to compute (A - B + C - R). 205 206 // In general, Wasm has no relocations for -B. It can only represent (A + C) 207 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can 208 // replace B to implement it: (A - R - K + C) 209 if (IsPCRel) { 210 Ctx.reportError( 211 Fixup.getLoc(), 212 "No relocation available to represent this relative expression"); 213 return; 214 } 215 216 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol()); 217 218 if (SymB.isUndefined()) { 219 Ctx.reportError(Fixup.getLoc(), 220 Twine("symbol '") + SymB.getName() + 221 "' can not be undefined in a subtraction expression"); 222 return; 223 } 224 225 assert(!SymB.isAbsolute() && "Should have been folded"); 226 const MCSection &SecB = SymB.getSection(); 227 if (&SecB != &FixupSection) { 228 Ctx.reportError(Fixup.getLoc(), 229 "Cannot represent a difference across sections"); 230 return; 231 } 232 233 uint64_t SymBOffset = Layout.getSymbolOffset(SymB); 234 uint64_t K = SymBOffset - FixupOffset; 235 IsPCRel = true; 236 C -= K; 237 } 238 239 // We either rejected the fixup or folded B into C at this point. 240 const MCSymbolRefExpr *RefA = Target.getSymA(); 241 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr; 242 243 bool ViaWeakRef = false; 244 if (SymA && SymA->isVariable()) { 245 const MCExpr *Expr = SymA->getVariableValue(); 246 if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { 247 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { 248 SymA = cast<MCSymbolWasm>(&Inner->getSymbol()); 249 ViaWeakRef = true; 250 } 251 } 252 } 253 254 // Put any constant offset in an addend. Offsets can be negative, and 255 // LLVM expects wrapping, in contrast to wasm's immediates which can't 256 // be negative and don't wrap. 257 FixedValue = 0; 258 259 if (SymA) { 260 if (ViaWeakRef) 261 llvm_unreachable("weakref used in reloc not yet implemented"); 262 else 263 SymA->setUsedInReloc(); 264 } 265 266 if (RefA) { 267 if (RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX) { 268 TypeIndexFixups.push_back(TypeIndexFixup(FixupOffset, SymA, 269 &FixupSection)); 270 return; 271 } 272 } 273 274 unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); 275 276 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); 277 278 if (FixupSection.hasInstructions()) 279 CodeRelocations.push_back(Rec); 280 else 281 DataRelocations.push_back(Rec); 282 } 283 284 namespace { 285 286 // The signature of a wasm function, in a struct capable of being used as a 287 // DenseMap key. 288 struct WasmFunctionType { 289 // Support empty and tombstone instances, needed by DenseMap. 290 enum { Plain, Empty, Tombstone } State; 291 292 // The return types of the function. 293 SmallVector<unsigned, 1> Returns; 294 295 // The parameter types of the function. 296 SmallVector<unsigned, 4> Params; 297 298 WasmFunctionType() : State(Plain) {} 299 300 bool operator==(const WasmFunctionType &Other) const { 301 return State == Other.State && Returns == Other.Returns && 302 Params == Other.Params; 303 } 304 }; 305 306 // Traits for using WasmFunctionType in a DenseMap. 307 struct WasmFunctionTypeDenseMapInfo { 308 static WasmFunctionType getEmptyKey() { 309 WasmFunctionType FuncTy; 310 FuncTy.State = WasmFunctionType::Empty; 311 return FuncTy; 312 } 313 static WasmFunctionType getTombstoneKey() { 314 WasmFunctionType FuncTy; 315 FuncTy.State = WasmFunctionType::Tombstone; 316 return FuncTy; 317 } 318 static unsigned getHashValue(const WasmFunctionType &FuncTy) { 319 uintptr_t Value = FuncTy.State; 320 for (unsigned Ret : FuncTy.Returns) 321 Value += DenseMapInfo<unsigned>::getHashValue(Ret); 322 for (unsigned Param : FuncTy.Params) 323 Value += DenseMapInfo<unsigned>::getHashValue(Param); 324 return Value; 325 } 326 static bool isEqual(const WasmFunctionType &LHS, 327 const WasmFunctionType &RHS) { 328 return LHS == RHS; 329 } 330 }; 331 332 // A wasm import to be written into the import section. 333 struct WasmImport { 334 StringRef ModuleName; 335 StringRef FieldName; 336 unsigned Kind; 337 uint32_t Type; 338 }; 339 340 // A wasm function to be written into the function section. 341 struct WasmFunction { 342 unsigned Type; 343 const MCSymbolWasm *Sym; 344 }; 345 346 // A wasm export to be written into the export section. 347 struct WasmExport { 348 StringRef FieldName; 349 unsigned Kind; 350 uint32_t Index; 351 }; 352 353 // A wasm global to be written into the global section. 354 struct WasmGlobal { 355 unsigned Type; 356 bool IsMutable; 357 uint32_t InitialValue; 358 }; 359 360 } // end anonymous namespace 361 362 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded 363 // to allow patching. 364 static void 365 WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 366 uint8_t Buffer[5]; 367 unsigned Padding = PaddingFor5ByteULEB128(X); 368 unsigned SizeLen = encodeULEB128(X, Buffer, Padding); 369 assert(SizeLen == 5); 370 Stream.pwrite((char *)Buffer, SizeLen, Offset); 371 } 372 373 // Write X as an signed LEB value at offset Offset in Stream, padded 374 // to allow patching. 375 static void 376 WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { 377 uint8_t Buffer[5]; 378 unsigned Padding = PaddingFor5ByteSLEB128(X); 379 unsigned SizeLen = encodeSLEB128(X, Buffer, Padding); 380 assert(SizeLen == 5); 381 Stream.pwrite((char *)Buffer, SizeLen, Offset); 382 } 383 384 // Write X as a plain integer value at offset Offset in Stream. 385 static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 386 uint8_t Buffer[4]; 387 support::endian::write32le(Buffer, X); 388 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); 389 } 390 391 // Compute a value to write into the code at the location covered 392 // by RelEntry. This value isn't used by the static linker, since 393 // we have addends; it just serves to make the code more readable 394 // and to make standalone wasm modules directly usable. 395 static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) { 396 const MCSymbolWasm *Sym = RelEntry.Symbol; 397 398 // For undefined symbols, use a hopefully invalid value. 399 if (!Sym->isDefined(false)) 400 return UINT32_MAX; 401 402 MCSectionWasm &Section = 403 cast<MCSectionWasm>(RelEntry.Symbol->getSection(false)); 404 uint64_t Address = Section.getSectionOffset() + RelEntry.Addend; 405 406 // Ignore overflow. LLVM allows address arithmetic to silently wrap. 407 uint32_t Value = Address; 408 409 return Value; 410 } 411 412 // Apply the portions of the relocation records that we can handle ourselves 413 // directly. 414 static void ApplyRelocations( 415 ArrayRef<WasmRelocationEntry> Relocations, 416 raw_pwrite_stream &Stream, 417 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 418 uint64_t ContentsOffset) 419 { 420 for (const WasmRelocationEntry &RelEntry : Relocations) { 421 uint64_t Offset = ContentsOffset + 422 RelEntry.FixupSection->getSectionOffset() + 423 RelEntry.Offset; 424 switch (RelEntry.Type) { 425 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: { 426 uint32_t Index = SymbolIndices[RelEntry.Symbol]; 427 assert(RelEntry.Addend == 0); 428 429 WritePatchableLEB(Stream, Index, Offset); 430 break; 431 } 432 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: { 433 uint32_t Index = SymbolIndices[RelEntry.Symbol]; 434 assert(RelEntry.Addend == 0); 435 436 WritePatchableSLEB(Stream, Index, Offset); 437 break; 438 } 439 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: { 440 uint32_t Value = ProvisionalValue(RelEntry); 441 442 WritePatchableSLEB(Stream, Value, Offset); 443 break; 444 } 445 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: { 446 uint32_t Value = ProvisionalValue(RelEntry); 447 448 WritePatchableLEB(Stream, Value, Offset); 449 break; 450 } 451 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { 452 uint32_t Index = SymbolIndices[RelEntry.Symbol]; 453 assert(RelEntry.Addend == 0); 454 455 WriteI32(Stream, Index, Offset); 456 break; 457 } 458 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: { 459 uint32_t Value = ProvisionalValue(RelEntry); 460 461 WriteI32(Stream, Value, Offset); 462 break; 463 } 464 default: 465 break; 466 } 467 } 468 } 469 470 // Write out the portions of the relocation records that the linker will 471 // need to handle. 472 static void WriteRelocations( 473 ArrayRef<WasmRelocationEntry> Relocations, 474 raw_pwrite_stream &Stream, 475 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) 476 { 477 for (const WasmRelocationEntry RelEntry : Relocations) { 478 encodeULEB128(RelEntry.Type, Stream); 479 480 uint64_t Offset = RelEntry.Offset + 481 RelEntry.FixupSection->getSectionOffset(); 482 uint32_t Index = SymbolIndices[RelEntry.Symbol]; 483 int64_t Addend = RelEntry.Addend; 484 485 switch (RelEntry.Type) { 486 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 487 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 488 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: 489 encodeULEB128(Offset, Stream); 490 encodeULEB128(Index, Stream); 491 assert(Addend == 0 && "addends not supported for functions"); 492 break; 493 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: 494 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: 495 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: 496 encodeULEB128(Offset, Stream); 497 encodeULEB128(Index, Stream); 498 encodeSLEB128(Addend, Stream); 499 break; 500 default: 501 llvm_unreachable("unsupported relocation type"); 502 } 503 } 504 } 505 506 void WasmObjectWriter::writeObject(MCAssembler &Asm, 507 const MCAsmLayout &Layout) { 508 MCContext &Ctx = Asm.getContext(); 509 unsigned PtrType = is64Bit() ? wasm::WASM_TYPE_I64 : wasm::WASM_TYPE_I32; 510 511 // Collect information from the available symbols. 512 DenseMap<WasmFunctionType, unsigned, WasmFunctionTypeDenseMapInfo> 513 FunctionTypeIndices; 514 SmallVector<WasmFunctionType, 4> FunctionTypes; 515 SmallVector<WasmFunction, 4> Functions; 516 SmallVector<uint32_t, 4> TableElems; 517 SmallVector<WasmGlobal, 4> Globals; 518 SmallVector<WasmImport, 4> Imports; 519 SmallVector<WasmExport, 4> Exports; 520 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices; 521 SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken; 522 unsigned NumFuncImports = 0; 523 unsigned NumGlobalImports = 0; 524 SmallVector<char, 0> DataBytes; 525 526 // Populate the IsAddressTaken set. 527 for (WasmRelocationEntry RelEntry : CodeRelocations) { 528 switch (RelEntry.Type) { 529 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 530 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: 531 IsAddressTaken.insert(RelEntry.Symbol); 532 break; 533 default: 534 break; 535 } 536 } 537 for (WasmRelocationEntry RelEntry : DataRelocations) { 538 switch (RelEntry.Type) { 539 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: 540 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: 541 IsAddressTaken.insert(RelEntry.Symbol); 542 break; 543 default: 544 break; 545 } 546 } 547 548 // Populate the Imports set. 549 for (const MCSymbol &S : Asm.symbols()) { 550 const auto &WS = static_cast<const MCSymbolWasm &>(S); 551 unsigned Type; 552 553 if (WS.isFunction()) { 554 // Prepare the function's type, if we haven't seen it yet. 555 WasmFunctionType F; 556 F.Returns = WS.getReturns(); 557 F.Params = WS.getParams(); 558 auto Pair = 559 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 560 if (Pair.second) 561 FunctionTypes.push_back(F); 562 563 Type = Pair.first->second; 564 } else { 565 Type = PtrType; 566 } 567 568 // If the symbol is not defined in this translation unit, import it. 569 if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) { 570 WasmImport Import; 571 Import.ModuleName = WS.getModuleName(); 572 Import.FieldName = WS.getName(); 573 574 if (WS.isFunction()) { 575 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; 576 Import.Type = Type; 577 SymbolIndices[&WS] = NumFuncImports; 578 ++NumFuncImports; 579 } else { 580 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; 581 Import.Type = Type; 582 SymbolIndices[&WS] = NumGlobalImports; 583 ++NumGlobalImports; 584 } 585 586 Imports.push_back(Import); 587 } 588 } 589 590 // In the special .global_variables section, we've encoded global 591 // variables used by the function. Translate them into the Globals 592 // list. 593 MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0); 594 if (!GlobalVars->getFragmentList().empty()) { 595 if (GlobalVars->getFragmentList().size() != 1) 596 report_fatal_error("only one .global_variables fragment supported"); 597 const MCFragment &Frag = *GlobalVars->begin(); 598 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) 599 report_fatal_error("only data supported in .global_variables"); 600 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag); 601 if (!DataFrag.getFixups().empty()) 602 report_fatal_error("fixups not supported in .global_variables"); 603 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 604 for (char p : Contents) { 605 WasmGlobal G; 606 G.Type = uint8_t(p); 607 G.IsMutable = true; 608 G.InitialValue = 0; 609 Globals.push_back(G); 610 } 611 } 612 613 // Handle defined symbols. 614 for (const MCSymbol &S : Asm.symbols()) { 615 // Ignore unnamed temporary symbols, which aren't ever exported, imported, 616 // or used in relocations. 617 if (S.isTemporary() && S.getName().empty()) 618 continue; 619 const auto &WS = static_cast<const MCSymbolWasm &>(S); 620 unsigned Index; 621 if (WS.isFunction()) { 622 // Prepare the function's type, if we haven't seen it yet. 623 WasmFunctionType F; 624 F.Returns = WS.getReturns(); 625 F.Params = WS.getParams(); 626 auto Pair = 627 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 628 if (Pair.second) 629 FunctionTypes.push_back(F); 630 631 unsigned Type = Pair.first->second; 632 633 if (WS.isDefined(/*SetUsed=*/false)) { 634 // A definition. Take the next available index. 635 Index = NumFuncImports + Functions.size(); 636 637 // Prepare the function. 638 WasmFunction Func; 639 Func.Type = Type; 640 Func.Sym = &WS; 641 SymbolIndices[&WS] = Index; 642 Functions.push_back(Func); 643 } else { 644 // An import; the index was assigned above. 645 Index = SymbolIndices.find(&WS)->second; 646 } 647 648 // If needed, prepare the function to be called indirectly. 649 if (IsAddressTaken.count(&WS)) 650 TableElems.push_back(Index); 651 } else { 652 // For now, ignore temporary non-function symbols. 653 if (S.isTemporary()) 654 continue; 655 656 if (WS.getOffset() != 0) 657 report_fatal_error("data sections must contain one variable each"); 658 if (!WS.getSize()) 659 report_fatal_error("data symbols must have a size set with .size"); 660 661 int64_t Size = 0; 662 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) 663 report_fatal_error(".size expression must be evaluatable"); 664 665 if (WS.isDefined(false)) { 666 MCSectionWasm &DataSection = 667 static_cast<MCSectionWasm &>(WS.getSection()); 668 669 if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection)) 670 report_fatal_error("data sections must contain at most one variable"); 671 672 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); 673 674 DataSection.setSectionOffset(DataBytes.size()); 675 676 for (MCSection::iterator I = DataSection.begin(), E = DataSection.end(); 677 I != E; ++I) { 678 const MCFragment &Frag = *I; 679 if (Frag.hasInstructions()) 680 report_fatal_error("only data supported in data sections"); 681 682 if (const MCAlignFragment *Align = dyn_cast<MCAlignFragment>(&Frag)) { 683 if (Align->getValueSize() != 1) 684 report_fatal_error("only byte values supported for alignment"); 685 // If nops are requested, use zeros, as this is the data section. 686 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); 687 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(), 688 Align->getAlignment()), 689 DataBytes.size() + 690 Align->getMaxBytesToEmit()); 691 DataBytes.resize(Size, Value); 692 } else if (const MCFillFragment *Fill = 693 dyn_cast<MCFillFragment>(&Frag)) { 694 DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); 695 } else { 696 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag); 697 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 698 699 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); 700 } 701 } 702 703 // For each external global, prepare a corresponding wasm global 704 // holding its address. 705 if (WS.isExternal()) { 706 Index = NumGlobalImports + Globals.size(); 707 708 WasmGlobal Global; 709 Global.Type = PtrType; 710 Global.IsMutable = false; 711 Global.InitialValue = DataSection.getSectionOffset(); 712 SymbolIndices[&WS] = Index; 713 Globals.push_back(Global); 714 } 715 } 716 } 717 718 // If the symbol is visible outside this translation unit, export it. 719 if (WS.isExternal()) { 720 assert(WS.isDefined(false)); 721 WasmExport Export; 722 Export.FieldName = WS.getName(); 723 Export.Index = Index; 724 725 if (WS.isFunction()) 726 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; 727 else 728 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; 729 730 Exports.push_back(Export); 731 } 732 } 733 734 // Add types for indirect function calls. 735 for (const TypeIndexFixup &Fixup : TypeIndexFixups) { 736 WasmFunctionType F; 737 F.Returns = Fixup.Symbol->getReturns(); 738 F.Params = Fixup.Symbol->getParams(); 739 auto Pair = 740 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 741 if (Pair.second) 742 FunctionTypes.push_back(F); 743 744 TypeIndexFixupTypes.push_back(Pair.first->second); 745 } 746 747 // Write out the Wasm header. 748 writeHeader(Asm); 749 750 SectionBookkeeping Section; 751 752 // === Type Section ========================================================= 753 if (!FunctionTypes.empty()) { 754 startSection(Section, wasm::WASM_SEC_TYPE); 755 756 encodeULEB128(FunctionTypes.size(), getStream()); 757 758 for (WasmFunctionType &FuncTy : FunctionTypes) { 759 write8(wasm::WASM_TYPE_FUNC); 760 encodeULEB128(FuncTy.Params.size(), getStream()); 761 for (unsigned Ty : FuncTy.Params) 762 write8(Ty); 763 encodeULEB128(FuncTy.Returns.size(), getStream()); 764 for (unsigned Ty : FuncTy.Returns) 765 write8(Ty); 766 } 767 768 endSection(Section); 769 } 770 771 // === Import Section ======================================================== 772 if (!Imports.empty()) { 773 startSection(Section, wasm::WASM_SEC_IMPORT); 774 775 encodeULEB128(Imports.size(), getStream()); 776 for (const WasmImport &Import : Imports) { 777 StringRef ModuleName = Import.ModuleName; 778 encodeULEB128(ModuleName.size(), getStream()); 779 writeBytes(ModuleName); 780 781 StringRef FieldName = Import.FieldName; 782 encodeULEB128(FieldName.size(), getStream()); 783 writeBytes(FieldName); 784 785 write8(Import.Kind); 786 787 switch (Import.Kind) { 788 case wasm::WASM_EXTERNAL_FUNCTION: 789 encodeULEB128(Import.Type, getStream()); 790 break; 791 case wasm::WASM_EXTERNAL_GLOBAL: 792 write8(Import.Type); 793 write8(0); // mutability 794 break; 795 default: 796 llvm_unreachable("unsupported import kind"); 797 } 798 } 799 800 endSection(Section); 801 } 802 803 // === Function Section ====================================================== 804 if (!Functions.empty()) { 805 startSection(Section, wasm::WASM_SEC_FUNCTION); 806 807 encodeULEB128(Functions.size(), getStream()); 808 for (const WasmFunction &Func : Functions) 809 encodeULEB128(Func.Type, getStream()); 810 811 endSection(Section); 812 } 813 814 // === Table Section ========================================================= 815 // For now, always emit the table section, since indirect calls are not 816 // valid without it. In the future, we could perhaps be more clever and omit 817 // it if there are no indirect calls. 818 startSection(Section, wasm::WASM_SEC_TABLE); 819 820 // The number of tables, fixed to 1 for now. 821 encodeULEB128(1, getStream()); 822 823 write8(wasm::WASM_TYPE_ANYFUNC); 824 825 encodeULEB128(0, getStream()); // flags 826 encodeULEB128(TableElems.size(), getStream()); // initial 827 828 endSection(Section); 829 830 // === Memory Section ======================================================== 831 // For now, always emit the memory section, since loads and stores are not 832 // valid without it. In the future, we could perhaps be more clever and omit 833 // it if there are no loads or stores. 834 startSection(Section, wasm::WASM_SEC_MEMORY); 835 836 encodeULEB128(1, getStream()); // number of memory spaces 837 838 encodeULEB128(0, getStream()); // flags 839 encodeULEB128(DataBytes.size(), getStream()); // initial 840 841 endSection(Section); 842 843 // === Global Section ======================================================== 844 if (!Globals.empty()) { 845 startSection(Section, wasm::WASM_SEC_GLOBAL); 846 847 encodeULEB128(Globals.size(), getStream()); 848 for (const WasmGlobal &Global : Globals) { 849 write8(Global.Type); 850 write8(Global.IsMutable); 851 852 write8(wasm::WASM_OPCODE_I32_CONST); 853 encodeSLEB128(Global.InitialValue, getStream()); // offset 854 write8(wasm::WASM_OPCODE_END); 855 } 856 857 endSection(Section); 858 } 859 860 // === Export Section ======================================================== 861 if (!Exports.empty()) { 862 startSection(Section, wasm::WASM_SEC_EXPORT); 863 864 encodeULEB128(Exports.size(), getStream()); 865 for (const WasmExport &Export : Exports) { 866 encodeULEB128(Export.FieldName.size(), getStream()); 867 writeBytes(Export.FieldName); 868 869 write8(Export.Kind); 870 871 encodeULEB128(Export.Index, getStream()); 872 } 873 874 endSection(Section); 875 } 876 877 #if 0 // TODO: Start Section 878 if (HaveStartFunction) { 879 // === Start Section ========================================================= 880 startSection(Section, wasm::WASM_SEC_START); 881 882 encodeSLEB128(StartFunction, getStream()); 883 884 endSection(Section); 885 } 886 #endif 887 888 // === Elem Section ========================================================== 889 if (!TableElems.empty()) { 890 startSection(Section, wasm::WASM_SEC_ELEM); 891 892 encodeULEB128(1, getStream()); // number of "segments" 893 encodeULEB128(0, getStream()); // the table index 894 895 // init expr for starting offset 896 write8(wasm::WASM_OPCODE_I32_CONST); 897 encodeSLEB128(0, getStream()); 898 write8(wasm::WASM_OPCODE_END); 899 900 encodeULEB128(TableElems.size(), getStream()); 901 for (uint32_t Elem : TableElems) 902 encodeULEB128(Elem, getStream()); 903 904 endSection(Section); 905 } 906 907 // === Code Section ========================================================== 908 if (!Functions.empty()) { 909 startSection(Section, wasm::WASM_SEC_CODE); 910 911 encodeULEB128(Functions.size(), getStream()); 912 913 for (const WasmFunction &Func : Functions) { 914 MCSectionWasm &FuncSection = 915 static_cast<MCSectionWasm &>(Func.Sym->getSection()); 916 917 if (Func.Sym->isVariable()) 918 report_fatal_error("weak symbols not supported yet"); 919 920 if (Func.Sym->getOffset() != 0) 921 report_fatal_error("function sections must contain one function each"); 922 923 if (!Func.Sym->getSize()) 924 report_fatal_error("function symbols must have a size set with .size"); 925 926 int64_t Size = 0; 927 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) 928 report_fatal_error(".size expression must be evaluatable"); 929 930 encodeULEB128(Size, getStream()); 931 932 FuncSection.setSectionOffset(getStream().tell() - 933 Section.ContentsOffset); 934 935 Asm.writeSectionData(&FuncSection, Layout); 936 } 937 938 // Apply the type index fixups for call_indirect etc. instructions. 939 for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) { 940 uint32_t Type = TypeIndexFixupTypes[i]; 941 unsigned Padding = PaddingFor5ByteULEB128(Type); 942 943 const TypeIndexFixup &Fixup = TypeIndexFixups[i]; 944 uint64_t Offset = Fixup.Offset + 945 Fixup.FixupSection->getSectionOffset(); 946 947 uint8_t Buffer[16]; 948 unsigned SizeLen = encodeULEB128(Type, Buffer, Padding); 949 assert(SizeLen == 5); 950 getStream().pwrite((char *)Buffer, SizeLen, 951 Section.ContentsOffset + Offset); 952 } 953 954 // Apply fixups. 955 ApplyRelocations(CodeRelocations, getStream(), SymbolIndices, 956 Section.ContentsOffset); 957 958 endSection(Section); 959 } 960 961 // === Data Section ========================================================== 962 if (!DataBytes.empty()) { 963 startSection(Section, wasm::WASM_SEC_DATA); 964 965 encodeULEB128(1, getStream()); // count 966 encodeULEB128(0, getStream()); // memory index 967 write8(wasm::WASM_OPCODE_I32_CONST); 968 encodeSLEB128(0, getStream()); // offset 969 write8(wasm::WASM_OPCODE_END); 970 encodeULEB128(DataBytes.size(), getStream()); // size 971 writeBytes(DataBytes); // data 972 973 // Apply fixups. 974 ApplyRelocations(DataRelocations, getStream(), SymbolIndices, 975 Section.ContentsOffset); 976 977 endSection(Section); 978 } 979 980 // === Name Section ========================================================== 981 if (NumFuncImports != 0 || !Functions.empty()) { 982 startSection(Section, wasm::WASM_SEC_CUSTOM, "name"); 983 984 encodeULEB128(NumFuncImports + Functions.size(), getStream()); 985 for (const WasmImport &Import : Imports) { 986 if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { 987 encodeULEB128(Import.FieldName.size(), getStream()); 988 writeBytes(Import.FieldName); 989 encodeULEB128(0, getStream()); // local count, meaningless for imports 990 } 991 } 992 for (const WasmFunction &Func : Functions) { 993 encodeULEB128(Func.Sym->getName().size(), getStream()); 994 writeBytes(Func.Sym->getName()); 995 996 // TODO: Local names. 997 encodeULEB128(0, getStream()); // local count 998 } 999 1000 endSection(Section); 1001 } 1002 1003 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md 1004 // for descriptions of the reloc sections. 1005 1006 // === Code Reloc Section ==================================================== 1007 if (!CodeRelocations.empty()) { 1008 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); 1009 1010 write8(wasm::WASM_SEC_CODE); 1011 1012 encodeULEB128(CodeRelocations.size(), getStream()); 1013 1014 WriteRelocations(CodeRelocations, getStream(), SymbolIndices); 1015 1016 endSection(Section); 1017 } 1018 1019 // === Data Reloc Section ==================================================== 1020 if (!DataRelocations.empty()) { 1021 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); 1022 1023 write8(wasm::WASM_SEC_DATA); 1024 1025 encodeULEB128(DataRelocations.size(), getStream()); 1026 1027 WriteRelocations(DataRelocations, getStream(), SymbolIndices); 1028 1029 endSection(Section); 1030 } 1031 1032 // TODO: Translate the .comment section to the output. 1033 1034 // TODO: Translate debug sections to the output. 1035 } 1036 1037 MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, 1038 raw_pwrite_stream &OS) { 1039 return new WasmObjectWriter(MOTW, OS); 1040 } 1041