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