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