118eafb6cSDan Gohman //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// 218eafb6cSDan Gohman // 318eafb6cSDan Gohman // The LLVM Compiler Infrastructure 418eafb6cSDan Gohman // 518eafb6cSDan Gohman // This file is distributed under the University of Illinois Open Source 618eafb6cSDan Gohman // License. See LICENSE.TXT for details. 718eafb6cSDan Gohman // 818eafb6cSDan Gohman //===----------------------------------------------------------------------===// 918eafb6cSDan Gohman // 1018eafb6cSDan Gohman // This file implements Wasm object file writer information. 1118eafb6cSDan Gohman // 1218eafb6cSDan Gohman //===----------------------------------------------------------------------===// 1318eafb6cSDan Gohman 1418eafb6cSDan Gohman #include "llvm/ADT/STLExtras.h" 1518eafb6cSDan Gohman #include "llvm/ADT/SmallPtrSet.h" 1618eafb6cSDan Gohman #include "llvm/MC/MCAsmBackend.h" 1718eafb6cSDan Gohman #include "llvm/MC/MCAsmInfo.h" 1818eafb6cSDan Gohman #include "llvm/MC/MCAsmLayout.h" 1918eafb6cSDan Gohman #include "llvm/MC/MCAssembler.h" 2018eafb6cSDan Gohman #include "llvm/MC/MCContext.h" 2118eafb6cSDan Gohman #include "llvm/MC/MCExpr.h" 2218eafb6cSDan Gohman #include "llvm/MC/MCFixupKindInfo.h" 2318eafb6cSDan Gohman #include "llvm/MC/MCObjectFileInfo.h" 2418eafb6cSDan Gohman #include "llvm/MC/MCObjectWriter.h" 2518eafb6cSDan Gohman #include "llvm/MC/MCSectionWasm.h" 2618eafb6cSDan Gohman #include "llvm/MC/MCSymbolWasm.h" 2718eafb6cSDan Gohman #include "llvm/MC/MCValue.h" 2818eafb6cSDan Gohman #include "llvm/MC/MCWasmObjectWriter.h" 29d934cb88SDan Gohman #include "llvm/Support/Casting.h" 3018eafb6cSDan Gohman #include "llvm/Support/Debug.h" 3118eafb6cSDan Gohman #include "llvm/Support/ErrorHandling.h" 32d934cb88SDan Gohman #include "llvm/Support/LEB128.h" 3318eafb6cSDan Gohman #include "llvm/Support/StringSaver.h" 347ea5adffSDan Gohman #include "llvm/Support/Wasm.h" 3518eafb6cSDan Gohman #include <vector> 3618eafb6cSDan Gohman 3718eafb6cSDan Gohman using namespace llvm; 3818eafb6cSDan Gohman 3918eafb6cSDan Gohman #undef DEBUG_TYPE 4018eafb6cSDan Gohman #define DEBUG_TYPE "reloc-info" 4118eafb6cSDan Gohman 4218eafb6cSDan Gohman namespace { 43*9e15f359SSam Clegg 44d934cb88SDan Gohman // For patching purposes, we need to remember where each section starts, both 45d934cb88SDan Gohman // for patching up the section size field, and for patching up references to 46d934cb88SDan Gohman // locations within the section. 47d934cb88SDan Gohman struct SectionBookkeeping { 48d934cb88SDan Gohman // Where the size of the section is written. 49d934cb88SDan Gohman uint64_t SizeOffset; 50d934cb88SDan Gohman // Where the contents of the section starts (after the header). 51d934cb88SDan Gohman uint64_t ContentsOffset; 52d934cb88SDan Gohman }; 53d934cb88SDan Gohman 54*9e15f359SSam Clegg // The signature of a wasm function, in a struct capable of being used as a 55*9e15f359SSam Clegg // DenseMap key. 56*9e15f359SSam Clegg struct WasmFunctionType { 57*9e15f359SSam Clegg // Support empty and tombstone instances, needed by DenseMap. 58*9e15f359SSam Clegg enum { Plain, Empty, Tombstone } State; 59*9e15f359SSam Clegg 60*9e15f359SSam Clegg // The return types of the function. 61*9e15f359SSam Clegg SmallVector<wasm::ValType, 1> Returns; 62*9e15f359SSam Clegg 63*9e15f359SSam Clegg // The parameter types of the function. 64*9e15f359SSam Clegg SmallVector<wasm::ValType, 4> Params; 65*9e15f359SSam Clegg 66*9e15f359SSam Clegg WasmFunctionType() : State(Plain) {} 67*9e15f359SSam Clegg 68*9e15f359SSam Clegg bool operator==(const WasmFunctionType &Other) const { 69*9e15f359SSam Clegg return State == Other.State && Returns == Other.Returns && 70*9e15f359SSam Clegg Params == Other.Params; 71*9e15f359SSam Clegg } 72*9e15f359SSam Clegg }; 73*9e15f359SSam Clegg 74*9e15f359SSam Clegg // Traits for using WasmFunctionType in a DenseMap. 75*9e15f359SSam Clegg struct WasmFunctionTypeDenseMapInfo { 76*9e15f359SSam Clegg static WasmFunctionType getEmptyKey() { 77*9e15f359SSam Clegg WasmFunctionType FuncTy; 78*9e15f359SSam Clegg FuncTy.State = WasmFunctionType::Empty; 79*9e15f359SSam Clegg return FuncTy; 80*9e15f359SSam Clegg } 81*9e15f359SSam Clegg static WasmFunctionType getTombstoneKey() { 82*9e15f359SSam Clegg WasmFunctionType FuncTy; 83*9e15f359SSam Clegg FuncTy.State = WasmFunctionType::Tombstone; 84*9e15f359SSam Clegg return FuncTy; 85*9e15f359SSam Clegg } 86*9e15f359SSam Clegg static unsigned getHashValue(const WasmFunctionType &FuncTy) { 87*9e15f359SSam Clegg uintptr_t Value = FuncTy.State; 88*9e15f359SSam Clegg for (wasm::ValType Ret : FuncTy.Returns) 89*9e15f359SSam Clegg Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret)); 90*9e15f359SSam Clegg for (wasm::ValType Param : FuncTy.Params) 91*9e15f359SSam Clegg Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param)); 92*9e15f359SSam Clegg return Value; 93*9e15f359SSam Clegg } 94*9e15f359SSam Clegg static bool isEqual(const WasmFunctionType &LHS, 95*9e15f359SSam Clegg const WasmFunctionType &RHS) { 96*9e15f359SSam Clegg return LHS == RHS; 97*9e15f359SSam Clegg } 98*9e15f359SSam Clegg }; 99*9e15f359SSam Clegg 100*9e15f359SSam Clegg // A wasm import to be written into the import section. 101*9e15f359SSam Clegg struct WasmImport { 102*9e15f359SSam Clegg StringRef ModuleName; 103*9e15f359SSam Clegg StringRef FieldName; 104*9e15f359SSam Clegg unsigned Kind; 105*9e15f359SSam Clegg int32_t Type; 106*9e15f359SSam Clegg }; 107*9e15f359SSam Clegg 108*9e15f359SSam Clegg // A wasm function to be written into the function section. 109*9e15f359SSam Clegg struct WasmFunction { 110*9e15f359SSam Clegg int32_t Type; 111*9e15f359SSam Clegg const MCSymbolWasm *Sym; 112*9e15f359SSam Clegg }; 113*9e15f359SSam Clegg 114*9e15f359SSam Clegg // A wasm export to be written into the export section. 115*9e15f359SSam Clegg struct WasmExport { 116*9e15f359SSam Clegg StringRef FieldName; 117*9e15f359SSam Clegg unsigned Kind; 118*9e15f359SSam Clegg uint32_t Index; 119*9e15f359SSam Clegg }; 120*9e15f359SSam Clegg 121*9e15f359SSam Clegg // A wasm global to be written into the global section. 122*9e15f359SSam Clegg struct WasmGlobal { 123*9e15f359SSam Clegg wasm::ValType Type; 124*9e15f359SSam Clegg bool IsMutable; 125*9e15f359SSam Clegg bool HasImport; 126*9e15f359SSam Clegg uint64_t InitialValue; 127*9e15f359SSam Clegg uint32_t ImportIndex; 128*9e15f359SSam Clegg }; 129*9e15f359SSam Clegg 13018eafb6cSDan Gohman class WasmObjectWriter : public MCObjectWriter { 13118eafb6cSDan Gohman /// Helper struct for containing some precomputed information on symbols. 13218eafb6cSDan Gohman struct WasmSymbolData { 13318eafb6cSDan Gohman const MCSymbolWasm *Symbol; 13418eafb6cSDan Gohman StringRef Name; 13518eafb6cSDan Gohman 13618eafb6cSDan Gohman // Support lexicographic sorting. 13718eafb6cSDan Gohman bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; } 13818eafb6cSDan Gohman }; 13918eafb6cSDan Gohman 14018eafb6cSDan Gohman /// The target specific Wasm writer instance. 14118eafb6cSDan Gohman std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter; 14218eafb6cSDan Gohman 143d934cb88SDan Gohman // Relocations for fixing up references in the code section. 144d934cb88SDan Gohman std::vector<WasmRelocationEntry> CodeRelocations; 145d934cb88SDan Gohman 146d934cb88SDan Gohman // Relocations for fixing up references in the data section. 147d934cb88SDan Gohman std::vector<WasmRelocationEntry> DataRelocations; 148d934cb88SDan Gohman 149d934cb88SDan Gohman // Fixups for call_indirect type indices. 150970d02c4SDan Gohman std::vector<WasmRelocationEntry> TypeIndexFixups; 151d934cb88SDan Gohman 152d934cb88SDan Gohman // Index values to use for fixing up call_indirect type indices. 153d934cb88SDan Gohman std::vector<uint32_t> TypeIndexFixupTypes; 154d934cb88SDan Gohman 15518eafb6cSDan Gohman // TargetObjectWriter wrappers. 15618eafb6cSDan Gohman bool is64Bit() const { return TargetObjectWriter->is64Bit(); } 15718eafb6cSDan Gohman unsigned getRelocType(MCContext &Ctx, const MCValue &Target, 15818eafb6cSDan Gohman const MCFixup &Fixup, bool IsPCRel) const { 15918eafb6cSDan Gohman return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); 16018eafb6cSDan Gohman } 16118eafb6cSDan Gohman 162d934cb88SDan Gohman void startSection(SectionBookkeeping &Section, unsigned SectionId, 163d934cb88SDan Gohman const char *Name = nullptr); 164d934cb88SDan Gohman void endSection(SectionBookkeeping &Section); 165d934cb88SDan Gohman 16618eafb6cSDan Gohman public: 16718eafb6cSDan Gohman WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS) 16818eafb6cSDan Gohman : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {} 16918eafb6cSDan Gohman 170d934cb88SDan Gohman private: 17118eafb6cSDan Gohman ~WasmObjectWriter() override; 17218eafb6cSDan Gohman 17318eafb6cSDan Gohman void writeHeader(const MCAssembler &Asm); 17418eafb6cSDan Gohman 17518eafb6cSDan Gohman void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, 17618eafb6cSDan Gohman const MCFragment *Fragment, const MCFixup &Fixup, 17718eafb6cSDan Gohman MCValue Target, bool &IsPCRel, 17818eafb6cSDan Gohman uint64_t &FixedValue) override; 17918eafb6cSDan Gohman 18018eafb6cSDan Gohman void executePostLayoutBinding(MCAssembler &Asm, 18118eafb6cSDan Gohman const MCAsmLayout &Layout) override; 18218eafb6cSDan Gohman 18318eafb6cSDan Gohman void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; 184*9e15f359SSam Clegg 185*9e15f359SSam Clegg void writeValueType(wasm::ValType Ty) { 186*9e15f359SSam Clegg encodeSLEB128(int32_t(Ty), getStream()); 187*9e15f359SSam Clegg } 188*9e15f359SSam Clegg 189*9e15f359SSam Clegg void writeTypeSection(const SmallVector<WasmFunctionType, 4> &FunctionTypes); 190*9e15f359SSam Clegg void writeImportSection(const SmallVector<WasmImport, 4> &Imports); 191*9e15f359SSam Clegg void writeFunctionSection(const SmallVector<WasmFunction, 4> &Functions); 192*9e15f359SSam Clegg void writeTableSection(const SmallVector<uint32_t, 4> &TableElems); 193*9e15f359SSam Clegg void writeMemorySection(const SmallVector<char, 0> &DataBytes); 194*9e15f359SSam Clegg void writeGlobalSection(const SmallVector<WasmGlobal, 4> &Globals); 195*9e15f359SSam Clegg void writeExportSection(const SmallVector<WasmExport, 4> &Exports); 196*9e15f359SSam Clegg void writeElemSection(const SmallVector<uint32_t, 4> &TableElems); 197*9e15f359SSam Clegg void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, 198*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 199*9e15f359SSam Clegg const SmallVector<WasmFunction, 4> &Functions); 200*9e15f359SSam Clegg uint64_t 201*9e15f359SSam Clegg writeDataSection(const SmallVector<char, 0> &DataBytes, 202*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices); 203*9e15f359SSam Clegg void writeNameSection(const SmallVector<WasmFunction, 4> &Functions, 204*9e15f359SSam Clegg const SmallVector<WasmImport, 4> &Imports, 205*9e15f359SSam Clegg uint32_t NumFuncImports); 206*9e15f359SSam Clegg void writeCodeRelocSection( 207*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices); 208*9e15f359SSam Clegg void writeDataRelocSection( 209*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 210*9e15f359SSam Clegg uint64_t DataSectionHeaderSize); 211*9e15f359SSam Clegg void writeLinkingMetaDataSection(bool HasStackPointer, 212*9e15f359SSam Clegg uint32_t StackPointerGlobal); 21318eafb6cSDan Gohman }; 214*9e15f359SSam Clegg 21518eafb6cSDan Gohman } // end anonymous namespace 21618eafb6cSDan Gohman 21718eafb6cSDan Gohman WasmObjectWriter::~WasmObjectWriter() {} 21818eafb6cSDan Gohman 219d934cb88SDan Gohman // Return the padding size to write a 32-bit value into a 5-byte ULEB128. 220d934cb88SDan Gohman static unsigned PaddingFor5ByteULEB128(uint32_t X) { 221d934cb88SDan Gohman return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u); 222d934cb88SDan Gohman } 223d934cb88SDan Gohman 224d934cb88SDan Gohman // Return the padding size to write a 32-bit value into a 5-byte SLEB128. 225d934cb88SDan Gohman static unsigned PaddingFor5ByteSLEB128(int32_t X) { 226d934cb88SDan Gohman return 5 - getSLEB128Size(X); 227d934cb88SDan Gohman } 228d934cb88SDan Gohman 229d934cb88SDan Gohman // Write out a section header and a patchable section size field. 230d934cb88SDan Gohman void WasmObjectWriter::startSection(SectionBookkeeping &Section, 231d934cb88SDan Gohman unsigned SectionId, 232d934cb88SDan Gohman const char *Name) { 233d934cb88SDan Gohman assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && 234d934cb88SDan Gohman "Only custom sections can have names"); 235d934cb88SDan Gohman 236e2688c43SDerek Schuff encodeULEB128(SectionId, getStream()); 237d934cb88SDan Gohman 238d934cb88SDan Gohman Section.SizeOffset = getStream().tell(); 239d934cb88SDan Gohman 240d934cb88SDan Gohman // The section size. We don't know the size yet, so reserve enough space 241d934cb88SDan Gohman // for any 32-bit value; we'll patch it later. 242d934cb88SDan Gohman encodeULEB128(UINT32_MAX, getStream()); 243d934cb88SDan Gohman 244d934cb88SDan Gohman // The position where the section starts, for measuring its size. 245d934cb88SDan Gohman Section.ContentsOffset = getStream().tell(); 246d934cb88SDan Gohman 247d934cb88SDan Gohman // Custom sections in wasm also have a string identifier. 248d934cb88SDan Gohman if (SectionId == wasm::WASM_SEC_CUSTOM) { 249d934cb88SDan Gohman encodeULEB128(strlen(Name), getStream()); 250d934cb88SDan Gohman writeBytes(Name); 251d934cb88SDan Gohman } 252d934cb88SDan Gohman } 253d934cb88SDan Gohman 254d934cb88SDan Gohman // Now that the section is complete and we know how big it is, patch up the 255d934cb88SDan Gohman // section size field at the start of the section. 256d934cb88SDan Gohman void WasmObjectWriter::endSection(SectionBookkeeping &Section) { 257d934cb88SDan Gohman uint64_t Size = getStream().tell() - Section.ContentsOffset; 258d934cb88SDan Gohman if (uint32_t(Size) != Size) 259d934cb88SDan Gohman report_fatal_error("section size does not fit in a uint32_t"); 260d934cb88SDan Gohman 261d934cb88SDan Gohman unsigned Padding = PaddingFor5ByteULEB128(Size); 262d934cb88SDan Gohman 263d934cb88SDan Gohman // Write the final section size to the payload_len field, which follows 264d934cb88SDan Gohman // the section id byte. 265d934cb88SDan Gohman uint8_t Buffer[16]; 266d934cb88SDan Gohman unsigned SizeLen = encodeULEB128(Size, Buffer, Padding); 267d934cb88SDan Gohman assert(SizeLen == 5); 268d934cb88SDan Gohman getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); 269d934cb88SDan Gohman } 270d934cb88SDan Gohman 27118eafb6cSDan Gohman // Emit the Wasm header. 27218eafb6cSDan Gohman void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { 2737ea5adffSDan Gohman writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic))); 2747ea5adffSDan Gohman writeLE32(wasm::WasmVersion); 27518eafb6cSDan Gohman } 27618eafb6cSDan Gohman 27718eafb6cSDan Gohman void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, 27818eafb6cSDan Gohman const MCAsmLayout &Layout) { 27918eafb6cSDan Gohman } 28018eafb6cSDan Gohman 28118eafb6cSDan Gohman void WasmObjectWriter::recordRelocation(MCAssembler &Asm, 28218eafb6cSDan Gohman const MCAsmLayout &Layout, 28318eafb6cSDan Gohman const MCFragment *Fragment, 28418eafb6cSDan Gohman const MCFixup &Fixup, MCValue Target, 28518eafb6cSDan Gohman bool &IsPCRel, uint64_t &FixedValue) { 286d934cb88SDan Gohman MCSectionWasm &FixupSection = cast<MCSectionWasm>(*Fragment->getParent()); 287d934cb88SDan Gohman uint64_t C = Target.getConstant(); 288d934cb88SDan Gohman uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); 289d934cb88SDan Gohman MCContext &Ctx = Asm.getContext(); 290d934cb88SDan Gohman 291d934cb88SDan Gohman if (const MCSymbolRefExpr *RefB = Target.getSymB()) { 292d934cb88SDan Gohman assert(RefB->getKind() == MCSymbolRefExpr::VK_None && 293d934cb88SDan Gohman "Should not have constructed this"); 294d934cb88SDan Gohman 295d934cb88SDan Gohman // Let A, B and C being the components of Target and R be the location of 296d934cb88SDan Gohman // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). 297d934cb88SDan Gohman // If it is pcrel, we want to compute (A - B + C - R). 298d934cb88SDan Gohman 299d934cb88SDan Gohman // In general, Wasm has no relocations for -B. It can only represent (A + C) 300d934cb88SDan Gohman // or (A + C - R). If B = R + K and the relocation is not pcrel, we can 301d934cb88SDan Gohman // replace B to implement it: (A - R - K + C) 302d934cb88SDan Gohman if (IsPCRel) { 303d934cb88SDan Gohman Ctx.reportError( 304d934cb88SDan Gohman Fixup.getLoc(), 305d934cb88SDan Gohman "No relocation available to represent this relative expression"); 306d934cb88SDan Gohman return; 307d934cb88SDan Gohman } 308d934cb88SDan Gohman 309d934cb88SDan Gohman const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol()); 310d934cb88SDan Gohman 311d934cb88SDan Gohman if (SymB.isUndefined()) { 312d934cb88SDan Gohman Ctx.reportError(Fixup.getLoc(), 313d934cb88SDan Gohman Twine("symbol '") + SymB.getName() + 314d934cb88SDan Gohman "' can not be undefined in a subtraction expression"); 315d934cb88SDan Gohman return; 316d934cb88SDan Gohman } 317d934cb88SDan Gohman 318d934cb88SDan Gohman assert(!SymB.isAbsolute() && "Should have been folded"); 319d934cb88SDan Gohman const MCSection &SecB = SymB.getSection(); 320d934cb88SDan Gohman if (&SecB != &FixupSection) { 321d934cb88SDan Gohman Ctx.reportError(Fixup.getLoc(), 322d934cb88SDan Gohman "Cannot represent a difference across sections"); 323d934cb88SDan Gohman return; 324d934cb88SDan Gohman } 325d934cb88SDan Gohman 326d934cb88SDan Gohman uint64_t SymBOffset = Layout.getSymbolOffset(SymB); 327d934cb88SDan Gohman uint64_t K = SymBOffset - FixupOffset; 328d934cb88SDan Gohman IsPCRel = true; 329d934cb88SDan Gohman C -= K; 330d934cb88SDan Gohman } 331d934cb88SDan Gohman 332d934cb88SDan Gohman // We either rejected the fixup or folded B into C at this point. 333d934cb88SDan Gohman const MCSymbolRefExpr *RefA = Target.getSymA(); 334d934cb88SDan Gohman const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr; 335d934cb88SDan Gohman 336d934cb88SDan Gohman bool ViaWeakRef = false; 337d934cb88SDan Gohman if (SymA && SymA->isVariable()) { 338d934cb88SDan Gohman const MCExpr *Expr = SymA->getVariableValue(); 339d934cb88SDan Gohman if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) { 340d934cb88SDan Gohman if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) { 341d934cb88SDan Gohman SymA = cast<MCSymbolWasm>(&Inner->getSymbol()); 342d934cb88SDan Gohman ViaWeakRef = true; 343d934cb88SDan Gohman } 344d934cb88SDan Gohman } 345d934cb88SDan Gohman } 346d934cb88SDan Gohman 347d934cb88SDan Gohman // Put any constant offset in an addend. Offsets can be negative, and 348d934cb88SDan Gohman // LLVM expects wrapping, in contrast to wasm's immediates which can't 349d934cb88SDan Gohman // be negative and don't wrap. 350d934cb88SDan Gohman FixedValue = 0; 351d934cb88SDan Gohman 352d934cb88SDan Gohman if (SymA) { 353d934cb88SDan Gohman if (ViaWeakRef) 354d934cb88SDan Gohman llvm_unreachable("weakref used in reloc not yet implemented"); 355d934cb88SDan Gohman else 356d934cb88SDan Gohman SymA->setUsedInReloc(); 357d934cb88SDan Gohman } 358d934cb88SDan Gohman 359d934cb88SDan Gohman if (RefA) { 360d934cb88SDan Gohman if (RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX) { 361970d02c4SDan Gohman assert(C == 0); 362970d02c4SDan Gohman WasmRelocationEntry Rec(FixupOffset, SymA, C, 363970d02c4SDan Gohman wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB, 364970d02c4SDan Gohman &FixupSection); 365970d02c4SDan Gohman TypeIndexFixups.push_back(Rec); 366d934cb88SDan Gohman return; 367d934cb88SDan Gohman } 368d934cb88SDan Gohman } 369d934cb88SDan Gohman 370d934cb88SDan Gohman unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel); 371d934cb88SDan Gohman 372d934cb88SDan Gohman WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); 373d934cb88SDan Gohman 374d934cb88SDan Gohman if (FixupSection.hasInstructions()) 375d934cb88SDan Gohman CodeRelocations.push_back(Rec); 376d934cb88SDan Gohman else 377d934cb88SDan Gohman DataRelocations.push_back(Rec); 378d934cb88SDan Gohman } 379d934cb88SDan Gohman 380d934cb88SDan Gohman // Write X as an (unsigned) LEB value at offset Offset in Stream, padded 381d934cb88SDan Gohman // to allow patching. 382d934cb88SDan Gohman static void 383d934cb88SDan Gohman WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 384d934cb88SDan Gohman uint8_t Buffer[5]; 385d934cb88SDan Gohman unsigned Padding = PaddingFor5ByteULEB128(X); 386d934cb88SDan Gohman unsigned SizeLen = encodeULEB128(X, Buffer, Padding); 387d934cb88SDan Gohman assert(SizeLen == 5); 388d934cb88SDan Gohman Stream.pwrite((char *)Buffer, SizeLen, Offset); 389d934cb88SDan Gohman } 390d934cb88SDan Gohman 391d934cb88SDan Gohman // Write X as an signed LEB value at offset Offset in Stream, padded 392d934cb88SDan Gohman // to allow patching. 393d934cb88SDan Gohman static void 394d934cb88SDan Gohman WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { 395d934cb88SDan Gohman uint8_t Buffer[5]; 396d934cb88SDan Gohman unsigned Padding = PaddingFor5ByteSLEB128(X); 397d934cb88SDan Gohman unsigned SizeLen = encodeSLEB128(X, Buffer, Padding); 398d934cb88SDan Gohman assert(SizeLen == 5); 399d934cb88SDan Gohman Stream.pwrite((char *)Buffer, SizeLen, Offset); 400d934cb88SDan Gohman } 401d934cb88SDan Gohman 402d934cb88SDan Gohman // Write X as a plain integer value at offset Offset in Stream. 403d934cb88SDan Gohman static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { 404d934cb88SDan Gohman uint8_t Buffer[4]; 405d934cb88SDan Gohman support::endian::write32le(Buffer, X); 406d934cb88SDan Gohman Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); 407d934cb88SDan Gohman } 408d934cb88SDan Gohman 409d934cb88SDan Gohman // Compute a value to write into the code at the location covered 410d934cb88SDan Gohman // by RelEntry. This value isn't used by the static linker, since 411d934cb88SDan Gohman // we have addends; it just serves to make the code more readable 412d934cb88SDan Gohman // and to make standalone wasm modules directly usable. 413d934cb88SDan Gohman static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) { 414d934cb88SDan Gohman const MCSymbolWasm *Sym = RelEntry.Symbol; 415d934cb88SDan Gohman 416d934cb88SDan Gohman // For undefined symbols, use a hopefully invalid value. 417d934cb88SDan Gohman if (!Sym->isDefined(false)) 418d934cb88SDan Gohman return UINT32_MAX; 419d934cb88SDan Gohman 420d934cb88SDan Gohman MCSectionWasm &Section = 421d934cb88SDan Gohman cast<MCSectionWasm>(RelEntry.Symbol->getSection(false)); 422d934cb88SDan Gohman uint64_t Address = Section.getSectionOffset() + RelEntry.Addend; 423d934cb88SDan Gohman 424d934cb88SDan Gohman // Ignore overflow. LLVM allows address arithmetic to silently wrap. 425d934cb88SDan Gohman uint32_t Value = Address; 426d934cb88SDan Gohman 427d934cb88SDan Gohman return Value; 428d934cb88SDan Gohman } 429d934cb88SDan Gohman 430d934cb88SDan Gohman // Apply the portions of the relocation records that we can handle ourselves 431d934cb88SDan Gohman // directly. 432d934cb88SDan Gohman static void ApplyRelocations( 433d934cb88SDan Gohman ArrayRef<WasmRelocationEntry> Relocations, 434d934cb88SDan Gohman raw_pwrite_stream &Stream, 435d934cb88SDan Gohman DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 436d934cb88SDan Gohman uint64_t ContentsOffset) 437d934cb88SDan Gohman { 438d934cb88SDan Gohman for (const WasmRelocationEntry &RelEntry : Relocations) { 439d934cb88SDan Gohman uint64_t Offset = ContentsOffset + 440d934cb88SDan Gohman RelEntry.FixupSection->getSectionOffset() + 441d934cb88SDan Gohman RelEntry.Offset; 442d934cb88SDan Gohman switch (RelEntry.Type) { 443d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: { 4441c154a61SSam Clegg assert(SymbolIndices.count(RelEntry.Symbol)); 445d934cb88SDan Gohman uint32_t Index = SymbolIndices[RelEntry.Symbol]; 446d934cb88SDan Gohman assert(RelEntry.Addend == 0); 447d934cb88SDan Gohman 448d934cb88SDan Gohman WritePatchableLEB(Stream, Index, Offset); 449d934cb88SDan Gohman break; 450d934cb88SDan Gohman } 451d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: { 4521c154a61SSam Clegg assert(SymbolIndices.count(RelEntry.Symbol)); 453d934cb88SDan Gohman uint32_t Index = SymbolIndices[RelEntry.Symbol]; 454d934cb88SDan Gohman assert(RelEntry.Addend == 0); 455d934cb88SDan Gohman 456d934cb88SDan Gohman WritePatchableSLEB(Stream, Index, Offset); 457d934cb88SDan Gohman break; 458d934cb88SDan Gohman } 459d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: { 460d934cb88SDan Gohman uint32_t Value = ProvisionalValue(RelEntry); 461d934cb88SDan Gohman 462d934cb88SDan Gohman WritePatchableSLEB(Stream, Value, Offset); 463d934cb88SDan Gohman break; 464d934cb88SDan Gohman } 465d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: { 466d934cb88SDan Gohman uint32_t Value = ProvisionalValue(RelEntry); 467d934cb88SDan Gohman 468d934cb88SDan Gohman WritePatchableLEB(Stream, Value, Offset); 469d934cb88SDan Gohman break; 470d934cb88SDan Gohman } 471d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { 4721c154a61SSam Clegg assert(SymbolIndices.count(RelEntry.Symbol)); 473d934cb88SDan Gohman uint32_t Index = SymbolIndices[RelEntry.Symbol]; 474d934cb88SDan Gohman assert(RelEntry.Addend == 0); 475d934cb88SDan Gohman 476d934cb88SDan Gohman WriteI32(Stream, Index, Offset); 477d934cb88SDan Gohman break; 478d934cb88SDan Gohman } 479d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: { 480d934cb88SDan Gohman uint32_t Value = ProvisionalValue(RelEntry); 481d934cb88SDan Gohman 482d934cb88SDan Gohman WriteI32(Stream, Value, Offset); 483d934cb88SDan Gohman break; 484d934cb88SDan Gohman } 485d934cb88SDan Gohman default: 486d934cb88SDan Gohman break; 487d934cb88SDan Gohman } 488d934cb88SDan Gohman } 489d934cb88SDan Gohman } 490d934cb88SDan Gohman 491d934cb88SDan Gohman // Write out the portions of the relocation records that the linker will 492d934cb88SDan Gohman // need to handle. 493a06de028SSam Clegg static void 494a06de028SSam Clegg WriteRelocations(ArrayRef<WasmRelocationEntry> Relocations, 495d934cb88SDan Gohman raw_pwrite_stream &Stream, 496a06de028SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 497a06de028SSam Clegg uint64_t HeaderSize) { 498d934cb88SDan Gohman for (const WasmRelocationEntry RelEntry : Relocations) { 499d934cb88SDan Gohman encodeULEB128(RelEntry.Type, Stream); 500d934cb88SDan Gohman 501d934cb88SDan Gohman uint64_t Offset = RelEntry.Offset + 502a06de028SSam Clegg RelEntry.FixupSection->getSectionOffset() + HeaderSize; 5031c154a61SSam Clegg assert(SymbolIndices.count(RelEntry.Symbol)); 504d934cb88SDan Gohman uint32_t Index = SymbolIndices[RelEntry.Symbol]; 505d934cb88SDan Gohman int64_t Addend = RelEntry.Addend; 506d934cb88SDan Gohman 507d934cb88SDan Gohman switch (RelEntry.Type) { 508d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: 509d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 510d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: 511d934cb88SDan Gohman encodeULEB128(Offset, Stream); 512d934cb88SDan Gohman encodeULEB128(Index, Stream); 513d934cb88SDan Gohman assert(Addend == 0 && "addends not supported for functions"); 514d934cb88SDan Gohman break; 515d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: 516d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: 517d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: 518d934cb88SDan Gohman encodeULEB128(Offset, Stream); 519d934cb88SDan Gohman encodeULEB128(Index, Stream); 520d934cb88SDan Gohman encodeSLEB128(Addend, Stream); 521d934cb88SDan Gohman break; 522d934cb88SDan Gohman default: 523d934cb88SDan Gohman llvm_unreachable("unsupported relocation type"); 524d934cb88SDan Gohman } 525d934cb88SDan Gohman } 52618eafb6cSDan Gohman } 52718eafb6cSDan Gohman 528970d02c4SDan Gohman // Write out the the type relocation records that the linker will 529970d02c4SDan Gohman // need to handle. 530970d02c4SDan Gohman static void WriteTypeRelocations( 531970d02c4SDan Gohman ArrayRef<WasmRelocationEntry> TypeIndexFixups, 532970d02c4SDan Gohman ArrayRef<uint32_t> TypeIndexFixupTypes, 533970d02c4SDan Gohman raw_pwrite_stream &Stream) 534970d02c4SDan Gohman { 535970d02c4SDan Gohman for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) { 536970d02c4SDan Gohman const WasmRelocationEntry &Fixup = TypeIndexFixups[i]; 537970d02c4SDan Gohman uint32_t Type = TypeIndexFixupTypes[i]; 538970d02c4SDan Gohman 539970d02c4SDan Gohman assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB); 540970d02c4SDan Gohman assert(Fixup.Addend == 0); 541970d02c4SDan Gohman 542970d02c4SDan Gohman uint64_t Offset = Fixup.Offset + 543970d02c4SDan Gohman Fixup.FixupSection->getSectionOffset(); 544970d02c4SDan Gohman 545970d02c4SDan Gohman encodeULEB128(Fixup.Type, Stream); 546970d02c4SDan Gohman encodeULEB128(Offset, Stream); 547970d02c4SDan Gohman encodeULEB128(Type, Stream); 548970d02c4SDan Gohman } 549970d02c4SDan Gohman } 550970d02c4SDan Gohman 551*9e15f359SSam Clegg void WasmObjectWriter::writeTypeSection( 552*9e15f359SSam Clegg const SmallVector<WasmFunctionType, 4> &FunctionTypes) { 553*9e15f359SSam Clegg if (FunctionTypes.empty()) 554*9e15f359SSam Clegg return; 555*9e15f359SSam Clegg 556*9e15f359SSam Clegg SectionBookkeeping Section; 557*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_TYPE); 558*9e15f359SSam Clegg 559*9e15f359SSam Clegg encodeULEB128(FunctionTypes.size(), getStream()); 560*9e15f359SSam Clegg 561*9e15f359SSam Clegg for (const WasmFunctionType &FuncTy : FunctionTypes) { 562*9e15f359SSam Clegg encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream()); 563*9e15f359SSam Clegg encodeULEB128(FuncTy.Params.size(), getStream()); 564*9e15f359SSam Clegg for (wasm::ValType Ty : FuncTy.Params) 565*9e15f359SSam Clegg writeValueType(Ty); 566*9e15f359SSam Clegg encodeULEB128(FuncTy.Returns.size(), getStream()); 567*9e15f359SSam Clegg for (wasm::ValType Ty : FuncTy.Returns) 568*9e15f359SSam Clegg writeValueType(Ty); 569*9e15f359SSam Clegg } 570*9e15f359SSam Clegg 571*9e15f359SSam Clegg endSection(Section); 572*9e15f359SSam Clegg } 573*9e15f359SSam Clegg 574*9e15f359SSam Clegg void WasmObjectWriter::writeImportSection( 575*9e15f359SSam Clegg const SmallVector<WasmImport, 4> &Imports) { 576*9e15f359SSam Clegg if (Imports.empty()) 577*9e15f359SSam Clegg return; 578*9e15f359SSam Clegg 579*9e15f359SSam Clegg SectionBookkeeping Section; 580*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_IMPORT); 581*9e15f359SSam Clegg 582*9e15f359SSam Clegg encodeULEB128(Imports.size(), getStream()); 583*9e15f359SSam Clegg for (const WasmImport &Import : Imports) { 584*9e15f359SSam Clegg StringRef ModuleName = Import.ModuleName; 585*9e15f359SSam Clegg encodeULEB128(ModuleName.size(), getStream()); 586*9e15f359SSam Clegg writeBytes(ModuleName); 587*9e15f359SSam Clegg 588*9e15f359SSam Clegg StringRef FieldName = Import.FieldName; 589*9e15f359SSam Clegg encodeULEB128(FieldName.size(), getStream()); 590*9e15f359SSam Clegg writeBytes(FieldName); 591*9e15f359SSam Clegg 592*9e15f359SSam Clegg encodeULEB128(Import.Kind, getStream()); 593*9e15f359SSam Clegg 594*9e15f359SSam Clegg switch (Import.Kind) { 595*9e15f359SSam Clegg case wasm::WASM_EXTERNAL_FUNCTION: 596*9e15f359SSam Clegg encodeULEB128(Import.Type, getStream()); 597*9e15f359SSam Clegg break; 598*9e15f359SSam Clegg case wasm::WASM_EXTERNAL_GLOBAL: 599*9e15f359SSam Clegg encodeSLEB128(int32_t(Import.Type), getStream()); 600*9e15f359SSam Clegg encodeULEB128(0, getStream()); // mutability 601*9e15f359SSam Clegg break; 602*9e15f359SSam Clegg default: 603*9e15f359SSam Clegg llvm_unreachable("unsupported import kind"); 604*9e15f359SSam Clegg } 605*9e15f359SSam Clegg } 606*9e15f359SSam Clegg 607*9e15f359SSam Clegg endSection(Section); 608*9e15f359SSam Clegg } 609*9e15f359SSam Clegg 610*9e15f359SSam Clegg void WasmObjectWriter::writeFunctionSection( 611*9e15f359SSam Clegg const SmallVector<WasmFunction, 4> &Functions) { 612*9e15f359SSam Clegg if (Functions.empty()) 613*9e15f359SSam Clegg return; 614*9e15f359SSam Clegg 615*9e15f359SSam Clegg SectionBookkeeping Section; 616*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_FUNCTION); 617*9e15f359SSam Clegg 618*9e15f359SSam Clegg encodeULEB128(Functions.size(), getStream()); 619*9e15f359SSam Clegg for (const WasmFunction &Func : Functions) 620*9e15f359SSam Clegg encodeULEB128(Func.Type, getStream()); 621*9e15f359SSam Clegg 622*9e15f359SSam Clegg endSection(Section); 623*9e15f359SSam Clegg } 624*9e15f359SSam Clegg 625*9e15f359SSam Clegg void WasmObjectWriter::writeTableSection( 626*9e15f359SSam Clegg const SmallVector<uint32_t, 4> &TableElems) { 627*9e15f359SSam Clegg // For now, always emit the table section, since indirect calls are not 628*9e15f359SSam Clegg // valid without it. In the future, we could perhaps be more clever and omit 629*9e15f359SSam Clegg // it if there are no indirect calls. 630*9e15f359SSam Clegg SectionBookkeeping Section; 631*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_TABLE); 632*9e15f359SSam Clegg 633*9e15f359SSam Clegg // The number of tables, fixed to 1 for now. 634*9e15f359SSam Clegg encodeULEB128(1, getStream()); 635*9e15f359SSam Clegg 636*9e15f359SSam Clegg encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream()); 637*9e15f359SSam Clegg 638*9e15f359SSam Clegg encodeULEB128(0, getStream()); // flags 639*9e15f359SSam Clegg encodeULEB128(TableElems.size(), getStream()); // initial 640*9e15f359SSam Clegg 641*9e15f359SSam Clegg endSection(Section); 642*9e15f359SSam Clegg } 643*9e15f359SSam Clegg 644*9e15f359SSam Clegg void WasmObjectWriter::writeMemorySection( 645*9e15f359SSam Clegg const SmallVector<char, 0> &DataBytes) { 646*9e15f359SSam Clegg // For now, always emit the memory section, since loads and stores are not 647*9e15f359SSam Clegg // valid without it. In the future, we could perhaps be more clever and omit 648*9e15f359SSam Clegg // it if there are no loads or stores. 649*9e15f359SSam Clegg SectionBookkeeping Section; 650*9e15f359SSam Clegg uint32_t NumPages = 651*9e15f359SSam Clegg (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize; 652*9e15f359SSam Clegg 653*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_MEMORY); 654*9e15f359SSam Clegg encodeULEB128(1, getStream()); // number of memory spaces 655*9e15f359SSam Clegg 656*9e15f359SSam Clegg encodeULEB128(0, getStream()); // flags 657*9e15f359SSam Clegg encodeULEB128(NumPages, getStream()); // initial 658*9e15f359SSam Clegg 659*9e15f359SSam Clegg endSection(Section); 660*9e15f359SSam Clegg } 661*9e15f359SSam Clegg 662*9e15f359SSam Clegg void WasmObjectWriter::writeGlobalSection( 663*9e15f359SSam Clegg const SmallVector<WasmGlobal, 4> &Globals) { 664*9e15f359SSam Clegg if (Globals.empty()) 665*9e15f359SSam Clegg return; 666*9e15f359SSam Clegg 667*9e15f359SSam Clegg SectionBookkeeping Section; 668*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_GLOBAL); 669*9e15f359SSam Clegg 670*9e15f359SSam Clegg encodeULEB128(Globals.size(), getStream()); 671*9e15f359SSam Clegg for (const WasmGlobal &Global : Globals) { 672*9e15f359SSam Clegg writeValueType(Global.Type); 673*9e15f359SSam Clegg write8(Global.IsMutable); 674*9e15f359SSam Clegg 675*9e15f359SSam Clegg if (Global.HasImport) { 676*9e15f359SSam Clegg assert(Global.InitialValue == 0); 677*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_GET_GLOBAL); 678*9e15f359SSam Clegg encodeULEB128(Global.ImportIndex, getStream()); 679*9e15f359SSam Clegg } else { 680*9e15f359SSam Clegg assert(Global.ImportIndex == 0); 681*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_I32_CONST); 682*9e15f359SSam Clegg encodeSLEB128(Global.InitialValue, getStream()); // offset 683*9e15f359SSam Clegg } 684*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_END); 685*9e15f359SSam Clegg } 686*9e15f359SSam Clegg 687*9e15f359SSam Clegg endSection(Section); 688*9e15f359SSam Clegg } 689*9e15f359SSam Clegg 690*9e15f359SSam Clegg void WasmObjectWriter::writeExportSection( 691*9e15f359SSam Clegg const SmallVector<WasmExport, 4> &Exports) { 692*9e15f359SSam Clegg if (Exports.empty()) 693*9e15f359SSam Clegg return; 694*9e15f359SSam Clegg 695*9e15f359SSam Clegg SectionBookkeeping Section; 696*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_EXPORT); 697*9e15f359SSam Clegg 698*9e15f359SSam Clegg encodeULEB128(Exports.size(), getStream()); 699*9e15f359SSam Clegg for (const WasmExport &Export : Exports) { 700*9e15f359SSam Clegg encodeULEB128(Export.FieldName.size(), getStream()); 701*9e15f359SSam Clegg writeBytes(Export.FieldName); 702*9e15f359SSam Clegg 703*9e15f359SSam Clegg encodeSLEB128(Export.Kind, getStream()); 704*9e15f359SSam Clegg 705*9e15f359SSam Clegg encodeULEB128(Export.Index, getStream()); 706*9e15f359SSam Clegg } 707*9e15f359SSam Clegg 708*9e15f359SSam Clegg endSection(Section); 709*9e15f359SSam Clegg } 710*9e15f359SSam Clegg 711*9e15f359SSam Clegg void WasmObjectWriter::writeElemSection( 712*9e15f359SSam Clegg const SmallVector<uint32_t, 4> &TableElems) { 713*9e15f359SSam Clegg if (TableElems.empty()) 714*9e15f359SSam Clegg return; 715*9e15f359SSam Clegg 716*9e15f359SSam Clegg SectionBookkeeping Section; 717*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_ELEM); 718*9e15f359SSam Clegg 719*9e15f359SSam Clegg encodeULEB128(1, getStream()); // number of "segments" 720*9e15f359SSam Clegg encodeULEB128(0, getStream()); // the table index 721*9e15f359SSam Clegg 722*9e15f359SSam Clegg // init expr for starting offset 723*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_I32_CONST); 724*9e15f359SSam Clegg encodeSLEB128(0, getStream()); 725*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_END); 726*9e15f359SSam Clegg 727*9e15f359SSam Clegg encodeULEB128(TableElems.size(), getStream()); 728*9e15f359SSam Clegg for (uint32_t Elem : TableElems) 729*9e15f359SSam Clegg encodeULEB128(Elem, getStream()); 730*9e15f359SSam Clegg 731*9e15f359SSam Clegg endSection(Section); 732*9e15f359SSam Clegg } 733*9e15f359SSam Clegg 734*9e15f359SSam Clegg void WasmObjectWriter::writeCodeSection( 735*9e15f359SSam Clegg const MCAssembler &Asm, const MCAsmLayout &Layout, 736*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 737*9e15f359SSam Clegg const SmallVector<WasmFunction, 4> &Functions) { 738*9e15f359SSam Clegg if (Functions.empty()) 739*9e15f359SSam Clegg return; 740*9e15f359SSam Clegg 741*9e15f359SSam Clegg SectionBookkeeping Section; 742*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_CODE); 743*9e15f359SSam Clegg 744*9e15f359SSam Clegg encodeULEB128(Functions.size(), getStream()); 745*9e15f359SSam Clegg 746*9e15f359SSam Clegg for (const WasmFunction &Func : Functions) { 747*9e15f359SSam Clegg MCSectionWasm &FuncSection = 748*9e15f359SSam Clegg static_cast<MCSectionWasm &>(Func.Sym->getSection()); 749*9e15f359SSam Clegg 750*9e15f359SSam Clegg if (Func.Sym->isVariable()) 751*9e15f359SSam Clegg report_fatal_error("weak symbols not supported yet"); 752*9e15f359SSam Clegg 753*9e15f359SSam Clegg if (Func.Sym->getOffset() != 0) 754*9e15f359SSam Clegg report_fatal_error("function sections must contain one function each"); 755*9e15f359SSam Clegg 756*9e15f359SSam Clegg if (!Func.Sym->getSize()) 757*9e15f359SSam Clegg report_fatal_error("function symbols must have a size set with .size"); 758*9e15f359SSam Clegg 759*9e15f359SSam Clegg int64_t Size = 0; 760*9e15f359SSam Clegg if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) 761*9e15f359SSam Clegg report_fatal_error(".size expression must be evaluatable"); 762*9e15f359SSam Clegg 763*9e15f359SSam Clegg encodeULEB128(Size, getStream()); 764*9e15f359SSam Clegg 765*9e15f359SSam Clegg FuncSection.setSectionOffset(getStream().tell() - 766*9e15f359SSam Clegg Section.ContentsOffset); 767*9e15f359SSam Clegg 768*9e15f359SSam Clegg Asm.writeSectionData(&FuncSection, Layout); 769*9e15f359SSam Clegg } 770*9e15f359SSam Clegg 771*9e15f359SSam Clegg // Apply the type index fixups for call_indirect etc. instructions. 772*9e15f359SSam Clegg for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) { 773*9e15f359SSam Clegg uint32_t Type = TypeIndexFixupTypes[i]; 774*9e15f359SSam Clegg unsigned Padding = PaddingFor5ByteULEB128(Type); 775*9e15f359SSam Clegg 776*9e15f359SSam Clegg const WasmRelocationEntry &Fixup = TypeIndexFixups[i]; 777*9e15f359SSam Clegg assert(Fixup.Addend == 0); 778*9e15f359SSam Clegg assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB); 779*9e15f359SSam Clegg uint64_t Offset = Fixup.Offset + 780*9e15f359SSam Clegg Fixup.FixupSection->getSectionOffset(); 781*9e15f359SSam Clegg 782*9e15f359SSam Clegg uint8_t Buffer[16]; 783*9e15f359SSam Clegg unsigned SizeLen = encodeULEB128(Type, Buffer, Padding); 784*9e15f359SSam Clegg assert(SizeLen == 5); 785*9e15f359SSam Clegg getStream().pwrite((char *)Buffer, SizeLen, 786*9e15f359SSam Clegg Section.ContentsOffset + Offset); 787*9e15f359SSam Clegg } 788*9e15f359SSam Clegg 789*9e15f359SSam Clegg // Apply fixups. 790*9e15f359SSam Clegg ApplyRelocations(CodeRelocations, getStream(), SymbolIndices, 791*9e15f359SSam Clegg Section.ContentsOffset); 792*9e15f359SSam Clegg 793*9e15f359SSam Clegg endSection(Section); 794*9e15f359SSam Clegg } 795*9e15f359SSam Clegg 796*9e15f359SSam Clegg uint64_t WasmObjectWriter::writeDataSection( 797*9e15f359SSam Clegg const SmallVector<char, 0> &DataBytes, 798*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) { 799*9e15f359SSam Clegg if (DataBytes.empty()) 800*9e15f359SSam Clegg return 0; 801*9e15f359SSam Clegg 802*9e15f359SSam Clegg SectionBookkeeping Section; 803*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_DATA); 804*9e15f359SSam Clegg 805*9e15f359SSam Clegg encodeULEB128(1, getStream()); // count 806*9e15f359SSam Clegg encodeULEB128(0, getStream()); // memory index 807*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_I32_CONST); 808*9e15f359SSam Clegg encodeSLEB128(0, getStream()); // offset 809*9e15f359SSam Clegg write8(wasm::WASM_OPCODE_END); 810*9e15f359SSam Clegg encodeULEB128(DataBytes.size(), getStream()); // size 811*9e15f359SSam Clegg uint32_t HeaderSize = getStream().tell() - Section.ContentsOffset; 812*9e15f359SSam Clegg writeBytes(DataBytes); // data 813*9e15f359SSam Clegg 814*9e15f359SSam Clegg // Apply fixups. 815*9e15f359SSam Clegg ApplyRelocations(DataRelocations, getStream(), SymbolIndices, 816*9e15f359SSam Clegg Section.ContentsOffset + HeaderSize); 817*9e15f359SSam Clegg 818*9e15f359SSam Clegg endSection(Section); 819*9e15f359SSam Clegg return HeaderSize; 820*9e15f359SSam Clegg } 821*9e15f359SSam Clegg 822*9e15f359SSam Clegg void WasmObjectWriter::writeNameSection( 823*9e15f359SSam Clegg const SmallVector<WasmFunction, 4> &Functions, 824*9e15f359SSam Clegg const SmallVector<WasmImport, 4> &Imports, 825*9e15f359SSam Clegg unsigned NumFuncImports) { 826*9e15f359SSam Clegg uint32_t TotalFunctions = NumFuncImports + Functions.size(); 827*9e15f359SSam Clegg if (TotalFunctions == 0) 828*9e15f359SSam Clegg return; 829*9e15f359SSam Clegg 830*9e15f359SSam Clegg SectionBookkeeping Section; 831*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_CUSTOM, "name"); 832*9e15f359SSam Clegg SectionBookkeeping SubSection; 833*9e15f359SSam Clegg startSection(SubSection, wasm::WASM_NAMES_FUNCTION); 834*9e15f359SSam Clegg 835*9e15f359SSam Clegg encodeULEB128(TotalFunctions, getStream()); 836*9e15f359SSam Clegg uint32_t Index = 0; 837*9e15f359SSam Clegg for (const WasmImport &Import : Imports) { 838*9e15f359SSam Clegg if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { 839*9e15f359SSam Clegg encodeULEB128(Index, getStream()); 840*9e15f359SSam Clegg encodeULEB128(Import.FieldName.size(), getStream()); 841*9e15f359SSam Clegg writeBytes(Import.FieldName); 842*9e15f359SSam Clegg ++Index; 843*9e15f359SSam Clegg } 844*9e15f359SSam Clegg } 845*9e15f359SSam Clegg for (const WasmFunction &Func : Functions) { 846*9e15f359SSam Clegg encodeULEB128(Index, getStream()); 847*9e15f359SSam Clegg encodeULEB128(Func.Sym->getName().size(), getStream()); 848*9e15f359SSam Clegg writeBytes(Func.Sym->getName()); 849*9e15f359SSam Clegg ++Index; 850*9e15f359SSam Clegg } 851*9e15f359SSam Clegg 852*9e15f359SSam Clegg endSection(SubSection); 853*9e15f359SSam Clegg endSection(Section); 854*9e15f359SSam Clegg } 855*9e15f359SSam Clegg 856*9e15f359SSam Clegg void WasmObjectWriter::writeCodeRelocSection( 857*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) { 858*9e15f359SSam Clegg // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md 859*9e15f359SSam Clegg // for descriptions of the reloc sections. 860*9e15f359SSam Clegg 861*9e15f359SSam Clegg if (CodeRelocations.empty()) 862*9e15f359SSam Clegg return; 863*9e15f359SSam Clegg 864*9e15f359SSam Clegg SectionBookkeeping Section; 865*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); 866*9e15f359SSam Clegg 867*9e15f359SSam Clegg encodeULEB128(wasm::WASM_SEC_CODE, getStream()); 868*9e15f359SSam Clegg encodeULEB128(CodeRelocations.size() + TypeIndexFixups.size(), getStream()); 869*9e15f359SSam Clegg 870*9e15f359SSam Clegg WriteRelocations(CodeRelocations, getStream(), SymbolIndices, 0); 871*9e15f359SSam Clegg WriteTypeRelocations(TypeIndexFixups, TypeIndexFixupTypes, getStream()); 872*9e15f359SSam Clegg 873*9e15f359SSam Clegg endSection(Section); 874*9e15f359SSam Clegg } 875*9e15f359SSam Clegg 876*9e15f359SSam Clegg void WasmObjectWriter::writeDataRelocSection( 877*9e15f359SSam Clegg DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices, 878*9e15f359SSam Clegg uint64_t DataSectionHeaderSize) { 879*9e15f359SSam Clegg // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md 880*9e15f359SSam Clegg // for descriptions of the reloc sections. 881*9e15f359SSam Clegg 882*9e15f359SSam Clegg if (DataRelocations.empty()) 883*9e15f359SSam Clegg return; 884*9e15f359SSam Clegg 885*9e15f359SSam Clegg SectionBookkeeping Section; 886*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); 887*9e15f359SSam Clegg 888*9e15f359SSam Clegg encodeULEB128(wasm::WASM_SEC_DATA, getStream()); 889*9e15f359SSam Clegg encodeULEB128(DataRelocations.size(), getStream()); 890*9e15f359SSam Clegg 891*9e15f359SSam Clegg WriteRelocations(DataRelocations, getStream(), SymbolIndices, 892*9e15f359SSam Clegg DataSectionHeaderSize); 893*9e15f359SSam Clegg 894*9e15f359SSam Clegg endSection(Section); 895*9e15f359SSam Clegg } 896*9e15f359SSam Clegg 897*9e15f359SSam Clegg void WasmObjectWriter::writeLinkingMetaDataSection( 898*9e15f359SSam Clegg bool HasStackPointer, uint32_t StackPointerGlobal) { 899*9e15f359SSam Clegg if (!HasStackPointer) 900*9e15f359SSam Clegg return; 901*9e15f359SSam Clegg SectionBookkeeping Section; 902*9e15f359SSam Clegg startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); 903*9e15f359SSam Clegg 904*9e15f359SSam Clegg encodeULEB128(1, getStream()); // count 905*9e15f359SSam Clegg 906*9e15f359SSam Clegg encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type 907*9e15f359SSam Clegg encodeULEB128(StackPointerGlobal, getStream()); // id 908*9e15f359SSam Clegg 909*9e15f359SSam Clegg endSection(Section); 910*9e15f359SSam Clegg } 911*9e15f359SSam Clegg 91218eafb6cSDan Gohman void WasmObjectWriter::writeObject(MCAssembler &Asm, 91318eafb6cSDan Gohman const MCAsmLayout &Layout) { 91482607f56SDan Gohman MCContext &Ctx = Asm.getContext(); 915b879539aSDerek Schuff wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; 916d934cb88SDan Gohman 917d934cb88SDan Gohman // Collect information from the available symbols. 918b879539aSDerek Schuff DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> 919d934cb88SDan Gohman FunctionTypeIndices; 920d934cb88SDan Gohman SmallVector<WasmFunctionType, 4> FunctionTypes; 921d934cb88SDan Gohman SmallVector<WasmFunction, 4> Functions; 922d934cb88SDan Gohman SmallVector<uint32_t, 4> TableElems; 923d934cb88SDan Gohman SmallVector<WasmGlobal, 4> Globals; 924d934cb88SDan Gohman SmallVector<WasmImport, 4> Imports; 925d934cb88SDan Gohman SmallVector<WasmExport, 4> Exports; 926d934cb88SDan Gohman DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices; 927d934cb88SDan Gohman SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken; 928d934cb88SDan Gohman unsigned NumFuncImports = 0; 929d934cb88SDan Gohman unsigned NumGlobalImports = 0; 930d934cb88SDan Gohman SmallVector<char, 0> DataBytes; 931970d02c4SDan Gohman uint32_t StackPointerGlobal = 0; 932970d02c4SDan Gohman bool HasStackPointer = false; 933d934cb88SDan Gohman 934d934cb88SDan Gohman // Populate the IsAddressTaken set. 935d934cb88SDan Gohman for (WasmRelocationEntry RelEntry : CodeRelocations) { 936d934cb88SDan Gohman switch (RelEntry.Type) { 937d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: 938d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: 939d934cb88SDan Gohman IsAddressTaken.insert(RelEntry.Symbol); 940d934cb88SDan Gohman break; 941d934cb88SDan Gohman default: 942d934cb88SDan Gohman break; 943d934cb88SDan Gohman } 944d934cb88SDan Gohman } 945d934cb88SDan Gohman for (WasmRelocationEntry RelEntry : DataRelocations) { 946d934cb88SDan Gohman switch (RelEntry.Type) { 947d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: 948d934cb88SDan Gohman case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: 949d934cb88SDan Gohman IsAddressTaken.insert(RelEntry.Symbol); 950d934cb88SDan Gohman break; 951d934cb88SDan Gohman default: 952d934cb88SDan Gohman break; 953d934cb88SDan Gohman } 954d934cb88SDan Gohman } 955d934cb88SDan Gohman 956d934cb88SDan Gohman // Populate the Imports set. 957d934cb88SDan Gohman for (const MCSymbol &S : Asm.symbols()) { 958d934cb88SDan Gohman const auto &WS = static_cast<const MCSymbolWasm &>(S); 959b879539aSDerek Schuff int32_t Type; 960d934cb88SDan Gohman 961d934cb88SDan Gohman if (WS.isFunction()) { 962d934cb88SDan Gohman // Prepare the function's type, if we haven't seen it yet. 963d934cb88SDan Gohman WasmFunctionType F; 964d934cb88SDan Gohman F.Returns = WS.getReturns(); 965d934cb88SDan Gohman F.Params = WS.getParams(); 966d934cb88SDan Gohman auto Pair = 967d934cb88SDan Gohman FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 968d934cb88SDan Gohman if (Pair.second) 969d934cb88SDan Gohman FunctionTypes.push_back(F); 970d934cb88SDan Gohman 971d934cb88SDan Gohman Type = Pair.first->second; 972d934cb88SDan Gohman } else { 973b879539aSDerek Schuff Type = int32_t(PtrType); 974d934cb88SDan Gohman } 975d934cb88SDan Gohman 976d934cb88SDan Gohman // If the symbol is not defined in this translation unit, import it. 977d934cb88SDan Gohman if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) { 978d934cb88SDan Gohman WasmImport Import; 979d934cb88SDan Gohman Import.ModuleName = WS.getModuleName(); 980d934cb88SDan Gohman Import.FieldName = WS.getName(); 981d934cb88SDan Gohman 982d934cb88SDan Gohman if (WS.isFunction()) { 983d934cb88SDan Gohman Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; 984d934cb88SDan Gohman Import.Type = Type; 985d934cb88SDan Gohman SymbolIndices[&WS] = NumFuncImports; 986d934cb88SDan Gohman ++NumFuncImports; 987d934cb88SDan Gohman } else { 988d934cb88SDan Gohman Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; 989d934cb88SDan Gohman Import.Type = Type; 990d934cb88SDan Gohman SymbolIndices[&WS] = NumGlobalImports; 991d934cb88SDan Gohman ++NumGlobalImports; 992d934cb88SDan Gohman } 993d934cb88SDan Gohman 994d934cb88SDan Gohman Imports.push_back(Import); 995d934cb88SDan Gohman } 996d934cb88SDan Gohman } 997d934cb88SDan Gohman 99882607f56SDan Gohman // In the special .global_variables section, we've encoded global 99982607f56SDan Gohman // variables used by the function. Translate them into the Globals 100082607f56SDan Gohman // list. 100182607f56SDan Gohman MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0); 100282607f56SDan Gohman if (!GlobalVars->getFragmentList().empty()) { 100382607f56SDan Gohman if (GlobalVars->getFragmentList().size() != 1) 100482607f56SDan Gohman report_fatal_error("only one .global_variables fragment supported"); 100582607f56SDan Gohman const MCFragment &Frag = *GlobalVars->begin(); 100682607f56SDan Gohman if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) 100782607f56SDan Gohman report_fatal_error("only data supported in .global_variables"); 100882607f56SDan Gohman const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag); 100982607f56SDan Gohman if (!DataFrag.getFixups().empty()) 101082607f56SDan Gohman report_fatal_error("fixups not supported in .global_variables"); 101182607f56SDan Gohman const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 1012970d02c4SDan Gohman for (const uint8_t *p = (const uint8_t *)Contents.data(), 1013970d02c4SDan Gohman *end = (const uint8_t *)Contents.data() + Contents.size(); 1014970d02c4SDan Gohman p != end; ) { 101582607f56SDan Gohman WasmGlobal G; 1016970d02c4SDan Gohman if (end - p < 3) 1017970d02c4SDan Gohman report_fatal_error("truncated global variable encoding"); 1018970d02c4SDan Gohman G.Type = wasm::ValType(int8_t(*p++)); 1019970d02c4SDan Gohman G.IsMutable = bool(*p++); 1020970d02c4SDan Gohman G.HasImport = bool(*p++); 1021970d02c4SDan Gohman if (G.HasImport) { 102282607f56SDan Gohman G.InitialValue = 0; 1023970d02c4SDan Gohman 1024970d02c4SDan Gohman WasmImport Import; 1025970d02c4SDan Gohman Import.ModuleName = (const char *)p; 1026970d02c4SDan Gohman const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p); 1027970d02c4SDan Gohman if (!nul) 1028970d02c4SDan Gohman report_fatal_error("global module name must be nul-terminated"); 1029970d02c4SDan Gohman p = nul + 1; 1030970d02c4SDan Gohman nul = (const uint8_t *)memchr(p, '\0', end - p); 1031970d02c4SDan Gohman if (!nul) 1032970d02c4SDan Gohman report_fatal_error("global base name must be nul-terminated"); 1033970d02c4SDan Gohman Import.FieldName = (const char *)p; 1034970d02c4SDan Gohman p = nul + 1; 1035970d02c4SDan Gohman 1036970d02c4SDan Gohman Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; 1037970d02c4SDan Gohman Import.Type = int32_t(G.Type); 1038970d02c4SDan Gohman 1039970d02c4SDan Gohman G.ImportIndex = NumGlobalImports; 1040970d02c4SDan Gohman ++NumGlobalImports; 1041970d02c4SDan Gohman 1042970d02c4SDan Gohman Imports.push_back(Import); 1043970d02c4SDan Gohman } else { 1044970d02c4SDan Gohman unsigned n; 1045970d02c4SDan Gohman G.InitialValue = decodeSLEB128(p, &n); 1046970d02c4SDan Gohman G.ImportIndex = 0; 1047c8da0c0bSSimon Pilgrim if ((ptrdiff_t)n > end - p) 1048970d02c4SDan Gohman report_fatal_error("global initial value must be valid SLEB128"); 1049970d02c4SDan Gohman p += n; 1050970d02c4SDan Gohman } 105182607f56SDan Gohman Globals.push_back(G); 105282607f56SDan Gohman } 105382607f56SDan Gohman } 105482607f56SDan Gohman 1055970d02c4SDan Gohman // In the special .stack_pointer section, we've encoded the stack pointer 1056970d02c4SDan Gohman // index. 1057970d02c4SDan Gohman MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0); 1058970d02c4SDan Gohman if (!StackPtr->getFragmentList().empty()) { 1059970d02c4SDan Gohman if (StackPtr->getFragmentList().size() != 1) 1060970d02c4SDan Gohman report_fatal_error("only one .stack_pointer fragment supported"); 1061970d02c4SDan Gohman const MCFragment &Frag = *StackPtr->begin(); 1062970d02c4SDan Gohman if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) 1063970d02c4SDan Gohman report_fatal_error("only data supported in .stack_pointer"); 1064970d02c4SDan Gohman const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag); 1065970d02c4SDan Gohman if (!DataFrag.getFixups().empty()) 1066970d02c4SDan Gohman report_fatal_error("fixups not supported in .stack_pointer"); 1067970d02c4SDan Gohman const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 1068970d02c4SDan Gohman if (Contents.size() != 4) 1069970d02c4SDan Gohman report_fatal_error("only one entry supported in .stack_pointer"); 1070970d02c4SDan Gohman HasStackPointer = true; 1071970d02c4SDan Gohman StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); 1072970d02c4SDan Gohman } 1073970d02c4SDan Gohman 1074d934cb88SDan Gohman // Handle defined symbols. 1075d934cb88SDan Gohman for (const MCSymbol &S : Asm.symbols()) { 1076d934cb88SDan Gohman // Ignore unnamed temporary symbols, which aren't ever exported, imported, 1077d934cb88SDan Gohman // or used in relocations. 1078d934cb88SDan Gohman if (S.isTemporary() && S.getName().empty()) 1079d934cb88SDan Gohman continue; 1080d934cb88SDan Gohman const auto &WS = static_cast<const MCSymbolWasm &>(S); 1081d934cb88SDan Gohman unsigned Index; 1082d934cb88SDan Gohman if (WS.isFunction()) { 1083d934cb88SDan Gohman // Prepare the function's type, if we haven't seen it yet. 1084d934cb88SDan Gohman WasmFunctionType F; 1085d934cb88SDan Gohman F.Returns = WS.getReturns(); 1086d934cb88SDan Gohman F.Params = WS.getParams(); 1087d934cb88SDan Gohman auto Pair = 1088d934cb88SDan Gohman FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 1089d934cb88SDan Gohman if (Pair.second) 1090d934cb88SDan Gohman FunctionTypes.push_back(F); 1091d934cb88SDan Gohman 1092b879539aSDerek Schuff int32_t Type = Pair.first->second; 1093d934cb88SDan Gohman 1094d934cb88SDan Gohman if (WS.isDefined(/*SetUsed=*/false)) { 1095d934cb88SDan Gohman // A definition. Take the next available index. 1096d934cb88SDan Gohman Index = NumFuncImports + Functions.size(); 1097d934cb88SDan Gohman 1098d934cb88SDan Gohman // Prepare the function. 1099d934cb88SDan Gohman WasmFunction Func; 1100d934cb88SDan Gohman Func.Type = Type; 1101d934cb88SDan Gohman Func.Sym = &WS; 1102d934cb88SDan Gohman SymbolIndices[&WS] = Index; 1103d934cb88SDan Gohman Functions.push_back(Func); 1104d934cb88SDan Gohman } else { 1105d934cb88SDan Gohman // An import; the index was assigned above. 1106d934cb88SDan Gohman Index = SymbolIndices.find(&WS)->second; 1107d934cb88SDan Gohman } 1108d934cb88SDan Gohman 1109d934cb88SDan Gohman // If needed, prepare the function to be called indirectly. 1110d934cb88SDan Gohman if (IsAddressTaken.count(&WS)) 1111d934cb88SDan Gohman TableElems.push_back(Index); 1112d934cb88SDan Gohman } else { 1113c38e947eSSam Clegg if (WS.isTemporary() && !WS.getSize()) 1114c38e947eSSam Clegg continue; 1115c38e947eSSam Clegg 1116c38e947eSSam Clegg if (WS.isDefined(false)) { 1117d934cb88SDan Gohman if (WS.getOffset() != 0) 1118c38e947eSSam Clegg report_fatal_error("data sections must contain one variable each: " + 1119c38e947eSSam Clegg WS.getName()); 1120d934cb88SDan Gohman if (!WS.getSize()) 1121c38e947eSSam Clegg report_fatal_error("data symbols must have a size set with .size: " + 1122c38e947eSSam Clegg WS.getName()); 1123d934cb88SDan Gohman 1124d934cb88SDan Gohman int64_t Size = 0; 1125d934cb88SDan Gohman if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) 1126d934cb88SDan Gohman report_fatal_error(".size expression must be evaluatable"); 1127d934cb88SDan Gohman 1128d934cb88SDan Gohman MCSectionWasm &DataSection = 1129d934cb88SDan Gohman static_cast<MCSectionWasm &>(WS.getSection()); 1130d934cb88SDan Gohman 1131d934cb88SDan Gohman if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection)) 1132d934cb88SDan Gohman report_fatal_error("data sections must contain at most one variable"); 1133d934cb88SDan Gohman 1134d934cb88SDan Gohman DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); 1135d934cb88SDan Gohman 1136d934cb88SDan Gohman DataSection.setSectionOffset(DataBytes.size()); 1137d934cb88SDan Gohman 1138d934cb88SDan Gohman for (MCSection::iterator I = DataSection.begin(), E = DataSection.end(); 1139d934cb88SDan Gohman I != E; ++I) { 1140d934cb88SDan Gohman const MCFragment &Frag = *I; 1141d934cb88SDan Gohman if (Frag.hasInstructions()) 1142d934cb88SDan Gohman report_fatal_error("only data supported in data sections"); 1143d934cb88SDan Gohman 1144d934cb88SDan Gohman if (const MCAlignFragment *Align = dyn_cast<MCAlignFragment>(&Frag)) { 1145d934cb88SDan Gohman if (Align->getValueSize() != 1) 1146d934cb88SDan Gohman report_fatal_error("only byte values supported for alignment"); 1147d934cb88SDan Gohman // If nops are requested, use zeros, as this is the data section. 1148d934cb88SDan Gohman uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); 1149d934cb88SDan Gohman uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(), 1150d934cb88SDan Gohman Align->getAlignment()), 1151d934cb88SDan Gohman DataBytes.size() + 1152d934cb88SDan Gohman Align->getMaxBytesToEmit()); 1153d934cb88SDan Gohman DataBytes.resize(Size, Value); 1154d934cb88SDan Gohman } else if (const MCFillFragment *Fill = 1155d934cb88SDan Gohman dyn_cast<MCFillFragment>(&Frag)) { 1156d934cb88SDan Gohman DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); 1157d934cb88SDan Gohman } else { 1158d934cb88SDan Gohman const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag); 1159d934cb88SDan Gohman const SmallVectorImpl<char> &Contents = DataFrag.getContents(); 1160d934cb88SDan Gohman 1161d934cb88SDan Gohman DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); 1162d934cb88SDan Gohman } 1163d934cb88SDan Gohman } 1164d934cb88SDan Gohman 11651c154a61SSam Clegg // For each global, prepare a corresponding wasm global holding its 11661c154a61SSam Clegg // address. For externals these will also be named exports. 1167d934cb88SDan Gohman Index = NumGlobalImports + Globals.size(); 1168d934cb88SDan Gohman 1169d934cb88SDan Gohman WasmGlobal Global; 1170d934cb88SDan Gohman Global.Type = PtrType; 1171d934cb88SDan Gohman Global.IsMutable = false; 1172970d02c4SDan Gohman Global.HasImport = false; 1173d934cb88SDan Gohman Global.InitialValue = DataSection.getSectionOffset(); 1174970d02c4SDan Gohman Global.ImportIndex = 0; 1175d934cb88SDan Gohman SymbolIndices[&WS] = Index; 1176d934cb88SDan Gohman Globals.push_back(Global); 1177d934cb88SDan Gohman } 1178d934cb88SDan Gohman } 1179d934cb88SDan Gohman 1180d934cb88SDan Gohman // If the symbol is visible outside this translation unit, export it. 1181d934cb88SDan Gohman if (WS.isExternal()) { 1182d934cb88SDan Gohman assert(WS.isDefined(false)); 1183d934cb88SDan Gohman WasmExport Export; 1184d934cb88SDan Gohman Export.FieldName = WS.getName(); 1185d934cb88SDan Gohman Export.Index = Index; 1186d934cb88SDan Gohman 1187d934cb88SDan Gohman if (WS.isFunction()) 1188d934cb88SDan Gohman Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; 1189d934cb88SDan Gohman else 1190d934cb88SDan Gohman Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; 1191d934cb88SDan Gohman 1192d934cb88SDan Gohman Exports.push_back(Export); 1193d934cb88SDan Gohman } 1194d934cb88SDan Gohman } 1195d934cb88SDan Gohman 1196d934cb88SDan Gohman // Add types for indirect function calls. 1197970d02c4SDan Gohman for (const WasmRelocationEntry &Fixup : TypeIndexFixups) { 1198970d02c4SDan Gohman assert(Fixup.Addend == 0); 1199970d02c4SDan Gohman assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB); 1200970d02c4SDan Gohman 1201d934cb88SDan Gohman WasmFunctionType F; 1202d934cb88SDan Gohman F.Returns = Fixup.Symbol->getReturns(); 1203d934cb88SDan Gohman F.Params = Fixup.Symbol->getParams(); 1204d934cb88SDan Gohman auto Pair = 1205d934cb88SDan Gohman FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); 1206d934cb88SDan Gohman if (Pair.second) 1207d934cb88SDan Gohman FunctionTypes.push_back(F); 1208d934cb88SDan Gohman 1209d934cb88SDan Gohman TypeIndexFixupTypes.push_back(Pair.first->second); 1210d934cb88SDan Gohman } 1211d934cb88SDan Gohman 121218eafb6cSDan Gohman // Write out the Wasm header. 121318eafb6cSDan Gohman writeHeader(Asm); 121418eafb6cSDan Gohman 1215*9e15f359SSam Clegg writeTypeSection(FunctionTypes); 1216*9e15f359SSam Clegg writeImportSection(Imports); 1217*9e15f359SSam Clegg writeFunctionSection(Functions); 1218*9e15f359SSam Clegg writeTableSection(TableElems); 1219*9e15f359SSam Clegg writeMemorySection(DataBytes); 1220*9e15f359SSam Clegg writeGlobalSection(Globals); 1221*9e15f359SSam Clegg writeExportSection(Exports); 1222*9e15f359SSam Clegg // TODO: Start Section 1223*9e15f359SSam Clegg writeElemSection(TableElems); 1224*9e15f359SSam Clegg writeCodeSection(Asm, Layout, SymbolIndices, Functions); 1225*9e15f359SSam Clegg uint64_t DataSectionHeaderSize = writeDataSection(DataBytes, SymbolIndices); 1226*9e15f359SSam Clegg writeNameSection(Functions, Imports, NumFuncImports); 1227*9e15f359SSam Clegg writeCodeRelocSection(SymbolIndices); 1228*9e15f359SSam Clegg writeDataRelocSection(SymbolIndices, DataSectionHeaderSize); 1229*9e15f359SSam Clegg writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal); 1230970d02c4SDan Gohman 1231d934cb88SDan Gohman // TODO: Translate the .comment section to the output. 1232d934cb88SDan Gohman // TODO: Translate debug sections to the output. 123318eafb6cSDan Gohman } 123418eafb6cSDan Gohman 123518eafb6cSDan Gohman MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW, 123618eafb6cSDan Gohman raw_pwrite_stream &OS) { 123718eafb6cSDan Gohman return new WasmObjectWriter(MOTW, OS); 123818eafb6cSDan Gohman } 1239