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