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