blob: 99d577dab9ef3c413675ba0f26afdba098679bca [file] [log] [blame]
Dan Gohman18eafb62017-02-22 01:23:18 +00001//===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements Wasm object file writer information.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/SmallPtrSet.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000016#include "llvm/BinaryFormat/Wasm.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000017#include "llvm/MC/MCAsmBackend.h"
18#include "llvm/MC/MCAsmInfo.h"
19#include "llvm/MC/MCAsmLayout.h"
20#include "llvm/MC/MCAssembler.h"
21#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCExpr.h"
23#include "llvm/MC/MCFixupKindInfo.h"
24#include "llvm/MC/MCObjectFileInfo.h"
25#include "llvm/MC/MCObjectWriter.h"
26#include "llvm/MC/MCSectionWasm.h"
27#include "llvm/MC/MCSymbolWasm.h"
28#include "llvm/MC/MCValue.h"
29#include "llvm/MC/MCWasmObjectWriter.h"
Dan Gohmand934cb82017-02-24 23:18:00 +000030#include "llvm/Support/Casting.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000031#include "llvm/Support/Debug.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000032#include "llvm/Support/ErrorHandling.h"
Dan Gohmand934cb82017-02-24 23:18:00 +000033#include "llvm/Support/LEB128.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000034#include "llvm/Support/StringSaver.h"
35#include <vector>
36
37using namespace llvm;
38
39#undef DEBUG_TYPE
40#define DEBUG_TYPE "reloc-info"
41
42namespace {
Sam Clegg9e15f352017-06-03 02:01:24 +000043
Dan Gohmand934cb82017-02-24 23:18:00 +000044// For patching purposes, we need to remember where each section starts, both
45// for patching up the section size field, and for patching up references to
46// locations within the section.
47struct SectionBookkeeping {
48 // Where the size of the section is written.
49 uint64_t SizeOffset;
50 // Where the contents of the section starts (after the header).
51 uint64_t ContentsOffset;
52};
53
Sam Clegg9e15f352017-06-03 02:01:24 +000054// The signature of a wasm function, in a struct capable of being used as a
55// DenseMap key.
56struct WasmFunctionType {
57 // Support empty and tombstone instances, needed by DenseMap.
58 enum { Plain, Empty, Tombstone } State;
59
60 // The return types of the function.
61 SmallVector<wasm::ValType, 1> Returns;
62
63 // The parameter types of the function.
64 SmallVector<wasm::ValType, 4> Params;
65
66 WasmFunctionType() : State(Plain) {}
67
68 bool operator==(const WasmFunctionType &Other) const {
69 return State == Other.State && Returns == Other.Returns &&
70 Params == Other.Params;
71 }
72};
73
74// Traits for using WasmFunctionType in a DenseMap.
75struct WasmFunctionTypeDenseMapInfo {
76 static WasmFunctionType getEmptyKey() {
77 WasmFunctionType FuncTy;
78 FuncTy.State = WasmFunctionType::Empty;
79 return FuncTy;
80 }
81 static WasmFunctionType getTombstoneKey() {
82 WasmFunctionType FuncTy;
83 FuncTy.State = WasmFunctionType::Tombstone;
84 return FuncTy;
85 }
86 static unsigned getHashValue(const WasmFunctionType &FuncTy) {
87 uintptr_t Value = FuncTy.State;
88 for (wasm::ValType Ret : FuncTy.Returns)
89 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret));
90 for (wasm::ValType Param : FuncTy.Params)
91 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param));
92 return Value;
93 }
94 static bool isEqual(const WasmFunctionType &LHS,
95 const WasmFunctionType &RHS) {
96 return LHS == RHS;
97 }
98};
99
100// A wasm import to be written into the import section.
101struct WasmImport {
102 StringRef ModuleName;
103 StringRef FieldName;
104 unsigned Kind;
105 int32_t Type;
106};
107
108// A wasm function to be written into the function section.
109struct WasmFunction {
110 int32_t Type;
111 const MCSymbolWasm *Sym;
112};
113
114// A wasm export to be written into the export section.
115struct WasmExport {
116 StringRef FieldName;
117 unsigned Kind;
118 uint32_t Index;
119};
120
121// A wasm global to be written into the global section.
122struct WasmGlobal {
123 wasm::ValType Type;
124 bool IsMutable;
125 bool HasImport;
126 uint64_t InitialValue;
127 uint32_t ImportIndex;
128};
129
Sam Clegg6dc65e92017-06-06 16:38:59 +0000130// Information about a single relocation.
131struct WasmRelocationEntry {
132 uint64_t Offset; // Where is the relocation.
133 const MCSymbolWasm *Symbol; // The symbol to relocate with.
134 int64_t Addend; // A value to add to the symbol.
135 unsigned Type; // The type of the relocation.
136 MCSectionWasm *FixupSection;// The section the relocation is targeting.
137
138 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
139 int64_t Addend, unsigned Type,
140 MCSectionWasm *FixupSection)
141 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
142 FixupSection(FixupSection) {}
143
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000144 bool hasAddend() const {
145 switch (Type) {
146 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
147 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
148 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
149 return true;
150 default:
151 return false;
152 }
153 }
154
Sam Clegg6dc65e92017-06-06 16:38:59 +0000155 void print(raw_ostream &Out) const {
156 Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend
157 << ", Type=" << Type << ", FixupSection=" << FixupSection;
158 }
159 void dump() const { print(errs()); }
160};
161
Dan Gohman18eafb62017-02-22 01:23:18 +0000162class WasmObjectWriter : public MCObjectWriter {
163 /// Helper struct for containing some precomputed information on symbols.
164 struct WasmSymbolData {
165 const MCSymbolWasm *Symbol;
166 StringRef Name;
167
168 // Support lexicographic sorting.
169 bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; }
170 };
171
172 /// The target specific Wasm writer instance.
173 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
174
Dan Gohmand934cb82017-02-24 23:18:00 +0000175 // Relocations for fixing up references in the code section.
176 std::vector<WasmRelocationEntry> CodeRelocations;
177
178 // Relocations for fixing up references in the data section.
179 std::vector<WasmRelocationEntry> DataRelocations;
180
Dan Gohmand934cb82017-02-24 23:18:00 +0000181 // Index values to use for fixing up call_indirect type indices.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000182 // Maps function symbols to the index of the type of the function
183 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
Sam Cleggd99f6072017-06-12 23:52:44 +0000184 // Maps function symbols to the table element index space. Used
185 // for TABLE_INDEX relocation types (i.e. address taken functions).
186 DenseMap<const MCSymbolWasm *, uint32_t> IndirectSymbolIndices;
187 // Maps function/global symbols to the function/global index space.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000188 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices;
189
190 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo>
191 FunctionTypeIndices;
Dan Gohmand934cb82017-02-24 23:18:00 +0000192
Dan Gohman18eafb62017-02-22 01:23:18 +0000193 // TargetObjectWriter wrappers.
194 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
195 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
196 const MCFixup &Fixup, bool IsPCRel) const {
197 return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
198 }
199
Dan Gohmand934cb82017-02-24 23:18:00 +0000200 void startSection(SectionBookkeeping &Section, unsigned SectionId,
201 const char *Name = nullptr);
202 void endSection(SectionBookkeeping &Section);
203
Dan Gohman18eafb62017-02-22 01:23:18 +0000204public:
205 WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS)
206 : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {}
207
Dan Gohmand934cb82017-02-24 23:18:00 +0000208private:
Dan Gohman18eafb62017-02-22 01:23:18 +0000209 ~WasmObjectWriter() override;
210
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000211 void reset() override {
212 CodeRelocations.clear();
213 DataRelocations.clear();
214 TypeIndices.clear();
215 SymbolIndices.clear();
Sam Cleggd99f6072017-06-12 23:52:44 +0000216 IndirectSymbolIndices.clear();
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000217 FunctionTypeIndices.clear();
218 MCObjectWriter::reset();
219 }
220
Dan Gohman18eafb62017-02-22 01:23:18 +0000221 void writeHeader(const MCAssembler &Asm);
222
223 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
224 const MCFragment *Fragment, const MCFixup &Fixup,
225 MCValue Target, bool &IsPCRel,
226 uint64_t &FixedValue) override;
227
228 void executePostLayoutBinding(MCAssembler &Asm,
229 const MCAsmLayout &Layout) override;
230
231 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
Sam Clegg9e15f352017-06-03 02:01:24 +0000232
233 void writeValueType(wasm::ValType Ty) {
234 encodeSLEB128(int32_t(Ty), getStream());
235 }
236
237 void writeTypeSection(const SmallVector<WasmFunctionType, 4> &FunctionTypes);
238 void writeImportSection(const SmallVector<WasmImport, 4> &Imports);
239 void writeFunctionSection(const SmallVector<WasmFunction, 4> &Functions);
Sam Cleggd99f6072017-06-12 23:52:44 +0000240 void writeTableSection(uint32_t NumElements);
Sam Clegg9e15f352017-06-03 02:01:24 +0000241 void writeMemorySection(const SmallVector<char, 0> &DataBytes);
242 void writeGlobalSection(const SmallVector<WasmGlobal, 4> &Globals);
243 void writeExportSection(const SmallVector<WasmExport, 4> &Exports);
244 void writeElemSection(const SmallVector<uint32_t, 4> &TableElems);
245 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
Sam Clegg9e15f352017-06-03 02:01:24 +0000246 const SmallVector<WasmFunction, 4> &Functions);
247 uint64_t
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000248 writeDataSection(const SmallVector<char, 0> &DataBytes);
Sam Clegg9e15f352017-06-03 02:01:24 +0000249 void writeNameSection(const SmallVector<WasmFunction, 4> &Functions,
250 const SmallVector<WasmImport, 4> &Imports,
251 uint32_t NumFuncImports);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000252 void writeCodeRelocSection();
253 void writeDataRelocSection(uint64_t DataSectionHeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +0000254 void writeLinkingMetaDataSection(bool HasStackPointer,
255 uint32_t StackPointerGlobal);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000256
257 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
258 uint64_t ContentsOffset);
259
260 void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations,
261 uint64_t HeaderSize);
262 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
Dan Gohman18eafb62017-02-22 01:23:18 +0000263};
Sam Clegg9e15f352017-06-03 02:01:24 +0000264
Dan Gohman18eafb62017-02-22 01:23:18 +0000265} // end anonymous namespace
266
267WasmObjectWriter::~WasmObjectWriter() {}
268
Dan Gohmand934cb82017-02-24 23:18:00 +0000269// Return the padding size to write a 32-bit value into a 5-byte ULEB128.
270static unsigned PaddingFor5ByteULEB128(uint32_t X) {
271 return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u);
272}
273
274// Return the padding size to write a 32-bit value into a 5-byte SLEB128.
275static unsigned PaddingFor5ByteSLEB128(int32_t X) {
276 return 5 - getSLEB128Size(X);
277}
278
279// Write out a section header and a patchable section size field.
280void WasmObjectWriter::startSection(SectionBookkeeping &Section,
281 unsigned SectionId,
282 const char *Name) {
283 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) &&
284 "Only custom sections can have names");
285
Derek Schuffe2688c42017-03-14 20:23:22 +0000286 encodeULEB128(SectionId, getStream());
Dan Gohmand934cb82017-02-24 23:18:00 +0000287
288 Section.SizeOffset = getStream().tell();
289
290 // The section size. We don't know the size yet, so reserve enough space
291 // for any 32-bit value; we'll patch it later.
292 encodeULEB128(UINT32_MAX, getStream());
293
294 // The position where the section starts, for measuring its size.
295 Section.ContentsOffset = getStream().tell();
296
297 // Custom sections in wasm also have a string identifier.
298 if (SectionId == wasm::WASM_SEC_CUSTOM) {
299 encodeULEB128(strlen(Name), getStream());
300 writeBytes(Name);
301 }
302}
303
304// Now that the section is complete and we know how big it is, patch up the
305// section size field at the start of the section.
306void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
307 uint64_t Size = getStream().tell() - Section.ContentsOffset;
308 if (uint32_t(Size) != Size)
309 report_fatal_error("section size does not fit in a uint32_t");
310
311 unsigned Padding = PaddingFor5ByteULEB128(Size);
312
313 // Write the final section size to the payload_len field, which follows
314 // the section id byte.
315 uint8_t Buffer[16];
316 unsigned SizeLen = encodeULEB128(Size, Buffer, Padding);
317 assert(SizeLen == 5);
318 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
319}
320
Dan Gohman18eafb62017-02-22 01:23:18 +0000321// Emit the Wasm header.
322void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
Dan Gohman7ea5adf2017-02-22 18:50:20 +0000323 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic)));
324 writeLE32(wasm::WasmVersion);
Dan Gohman18eafb62017-02-22 01:23:18 +0000325}
326
327void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
328 const MCAsmLayout &Layout) {
329}
330
331void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
332 const MCAsmLayout &Layout,
333 const MCFragment *Fragment,
334 const MCFixup &Fixup, MCValue Target,
335 bool &IsPCRel, uint64_t &FixedValue) {
Dan Gohmand934cb82017-02-24 23:18:00 +0000336 MCSectionWasm &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
337 uint64_t C = Target.getConstant();
338 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
339 MCContext &Ctx = Asm.getContext();
340
341 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
342 assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
343 "Should not have constructed this");
344
345 // Let A, B and C being the components of Target and R be the location of
346 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
347 // If it is pcrel, we want to compute (A - B + C - R).
348
349 // In general, Wasm has no relocations for -B. It can only represent (A + C)
350 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
351 // replace B to implement it: (A - R - K + C)
352 if (IsPCRel) {
353 Ctx.reportError(
354 Fixup.getLoc(),
355 "No relocation available to represent this relative expression");
356 return;
357 }
358
359 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
360
361 if (SymB.isUndefined()) {
362 Ctx.reportError(Fixup.getLoc(),
363 Twine("symbol '") + SymB.getName() +
364 "' can not be undefined in a subtraction expression");
365 return;
366 }
367
368 assert(!SymB.isAbsolute() && "Should have been folded");
369 const MCSection &SecB = SymB.getSection();
370 if (&SecB != &FixupSection) {
371 Ctx.reportError(Fixup.getLoc(),
372 "Cannot represent a difference across sections");
373 return;
374 }
375
376 uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
377 uint64_t K = SymBOffset - FixupOffset;
378 IsPCRel = true;
379 C -= K;
380 }
381
382 // We either rejected the fixup or folded B into C at this point.
383 const MCSymbolRefExpr *RefA = Target.getSymA();
384 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
385
386 bool ViaWeakRef = false;
387 if (SymA && SymA->isVariable()) {
388 const MCExpr *Expr = SymA->getVariableValue();
389 if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
390 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
391 SymA = cast<MCSymbolWasm>(&Inner->getSymbol());
392 ViaWeakRef = true;
393 }
394 }
395 }
396
397 // Put any constant offset in an addend. Offsets can be negative, and
398 // LLVM expects wrapping, in contrast to wasm's immediates which can't
399 // be negative and don't wrap.
400 FixedValue = 0;
401
402 if (SymA) {
403 if (ViaWeakRef)
404 llvm_unreachable("weakref used in reloc not yet implemented");
405 else
406 SymA->setUsedInReloc();
407 }
408
Dan Gohmand934cb82017-02-24 23:18:00 +0000409 unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel);
Dan Gohmand934cb82017-02-24 23:18:00 +0000410 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
411
412 if (FixupSection.hasInstructions())
413 CodeRelocations.push_back(Rec);
414 else
415 DataRelocations.push_back(Rec);
416}
417
Dan Gohmand934cb82017-02-24 23:18:00 +0000418// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
419// to allow patching.
420static void
421WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
422 uint8_t Buffer[5];
423 unsigned Padding = PaddingFor5ByteULEB128(X);
424 unsigned SizeLen = encodeULEB128(X, Buffer, Padding);
425 assert(SizeLen == 5);
426 Stream.pwrite((char *)Buffer, SizeLen, Offset);
427}
428
429// Write X as an signed LEB value at offset Offset in Stream, padded
430// to allow patching.
431static void
432WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
433 uint8_t Buffer[5];
434 unsigned Padding = PaddingFor5ByteSLEB128(X);
435 unsigned SizeLen = encodeSLEB128(X, Buffer, Padding);
436 assert(SizeLen == 5);
437 Stream.pwrite((char *)Buffer, SizeLen, Offset);
438}
439
440// Write X as a plain integer value at offset Offset in Stream.
441static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
442 uint8_t Buffer[4];
443 support::endian::write32le(Buffer, X);
444 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
445}
446
447// Compute a value to write into the code at the location covered
448// by RelEntry. This value isn't used by the static linker, since
449// we have addends; it just serves to make the code more readable
450// and to make standalone wasm modules directly usable.
451static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) {
452 const MCSymbolWasm *Sym = RelEntry.Symbol;
453
454 // For undefined symbols, use a hopefully invalid value.
455 if (!Sym->isDefined(false))
456 return UINT32_MAX;
457
458 MCSectionWasm &Section =
459 cast<MCSectionWasm>(RelEntry.Symbol->getSection(false));
460 uint64_t Address = Section.getSectionOffset() + RelEntry.Addend;
461
462 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
463 uint32_t Value = Address;
464
465 return Value;
466}
467
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000468uint32_t WasmObjectWriter::getRelocationIndexValue(
469 const WasmRelocationEntry &RelEntry) {
470 switch (RelEntry.Type) {
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000471 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
472 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
Sam Cleggd99f6072017-06-12 23:52:44 +0000473 assert(IndirectSymbolIndices.count(RelEntry.Symbol));
474 return IndirectSymbolIndices[RelEntry.Symbol];
475 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000476 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
477 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
478 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
479 assert(SymbolIndices.count(RelEntry.Symbol));
480 return SymbolIndices[RelEntry.Symbol];
481 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
482 assert(TypeIndices.count(RelEntry.Symbol));
483 return TypeIndices[RelEntry.Symbol];
484 default:
485 llvm_unreachable("invalid relocation type");
486 }
487}
488
Dan Gohmand934cb82017-02-24 23:18:00 +0000489// Apply the portions of the relocation records that we can handle ourselves
490// directly.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000491void WasmObjectWriter::applyRelocations(
492 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
493 raw_pwrite_stream &Stream = getStream();
Dan Gohmand934cb82017-02-24 23:18:00 +0000494 for (const WasmRelocationEntry &RelEntry : Relocations) {
495 uint64_t Offset = ContentsOffset +
496 RelEntry.FixupSection->getSectionOffset() +
497 RelEntry.Offset;
Dan Gohmand934cb82017-02-24 23:18:00 +0000498
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000499 switch (RelEntry.Type) {
500 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
501 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
502 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: {
503 uint32_t Index = getRelocationIndexValue(RelEntry);
504 WritePatchableSLEB(Stream, Index, Offset);
Dan Gohmand934cb82017-02-24 23:18:00 +0000505 break;
506 }
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000507 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
508 uint32_t Index = getRelocationIndexValue(RelEntry);
509 WriteI32(Stream, Index, Offset);
Dan Gohmand934cb82017-02-24 23:18:00 +0000510 break;
511 }
512 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: {
513 uint32_t Value = ProvisionalValue(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +0000514 WritePatchableSLEB(Stream, Value, Offset);
515 break;
516 }
517 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: {
518 uint32_t Value = ProvisionalValue(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +0000519 WritePatchableLEB(Stream, Value, Offset);
520 break;
521 }
Dan Gohmand934cb82017-02-24 23:18:00 +0000522 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: {
523 uint32_t Value = ProvisionalValue(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +0000524 WriteI32(Stream, Value, Offset);
525 break;
526 }
527 default:
Dan Gohmand934cb82017-02-24 23:18:00 +0000528 llvm_unreachable("unsupported relocation type");
529 }
530 }
Dan Gohman18eafb62017-02-22 01:23:18 +0000531}
532
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000533// Write out the portions of the relocation records that the linker will
Dan Gohman970d02c2017-03-30 23:58:19 +0000534// need to handle.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000535void WasmObjectWriter::writeRelocations(
536 ArrayRef<WasmRelocationEntry> Relocations, uint64_t HeaderSize) {
537 raw_pwrite_stream &Stream = getStream();
538 for (const WasmRelocationEntry& RelEntry : Relocations) {
Dan Gohman970d02c2017-03-30 23:58:19 +0000539
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000540 uint64_t Offset = RelEntry.Offset +
541 RelEntry.FixupSection->getSectionOffset() + HeaderSize;
542 uint32_t Index = getRelocationIndexValue(RelEntry);
Dan Gohman970d02c2017-03-30 23:58:19 +0000543
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000544 encodeULEB128(RelEntry.Type, Stream);
Dan Gohman970d02c2017-03-30 23:58:19 +0000545 encodeULEB128(Offset, Stream);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000546 encodeULEB128(Index, Stream);
547 if (RelEntry.hasAddend())
548 encodeSLEB128(RelEntry.Addend, Stream);
Dan Gohman970d02c2017-03-30 23:58:19 +0000549 }
550}
551
Sam Clegg9e15f352017-06-03 02:01:24 +0000552void WasmObjectWriter::writeTypeSection(
553 const SmallVector<WasmFunctionType, 4> &FunctionTypes) {
554 if (FunctionTypes.empty())
555 return;
556
557 SectionBookkeeping Section;
558 startSection(Section, wasm::WASM_SEC_TYPE);
559
560 encodeULEB128(FunctionTypes.size(), getStream());
561
562 for (const WasmFunctionType &FuncTy : FunctionTypes) {
563 encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream());
564 encodeULEB128(FuncTy.Params.size(), getStream());
565 for (wasm::ValType Ty : FuncTy.Params)
566 writeValueType(Ty);
567 encodeULEB128(FuncTy.Returns.size(), getStream());
568 for (wasm::ValType Ty : FuncTy.Returns)
569 writeValueType(Ty);
570 }
571
572 endSection(Section);
573}
574
575void WasmObjectWriter::writeImportSection(
576 const SmallVector<WasmImport, 4> &Imports) {
577 if (Imports.empty())
578 return;
579
580 SectionBookkeeping Section;
581 startSection(Section, wasm::WASM_SEC_IMPORT);
582
583 encodeULEB128(Imports.size(), getStream());
584 for (const WasmImport &Import : Imports) {
585 StringRef ModuleName = Import.ModuleName;
586 encodeULEB128(ModuleName.size(), getStream());
587 writeBytes(ModuleName);
588
589 StringRef FieldName = Import.FieldName;
590 encodeULEB128(FieldName.size(), getStream());
591 writeBytes(FieldName);
592
593 encodeULEB128(Import.Kind, getStream());
594
595 switch (Import.Kind) {
596 case wasm::WASM_EXTERNAL_FUNCTION:
597 encodeULEB128(Import.Type, getStream());
598 break;
599 case wasm::WASM_EXTERNAL_GLOBAL:
600 encodeSLEB128(int32_t(Import.Type), getStream());
601 encodeULEB128(0, getStream()); // mutability
602 break;
603 default:
604 llvm_unreachable("unsupported import kind");
605 }
606 }
607
608 endSection(Section);
609}
610
611void WasmObjectWriter::writeFunctionSection(
612 const SmallVector<WasmFunction, 4> &Functions) {
613 if (Functions.empty())
614 return;
615
616 SectionBookkeeping Section;
617 startSection(Section, wasm::WASM_SEC_FUNCTION);
618
619 encodeULEB128(Functions.size(), getStream());
620 for (const WasmFunction &Func : Functions)
621 encodeULEB128(Func.Type, getStream());
622
623 endSection(Section);
624}
625
Sam Cleggd99f6072017-06-12 23:52:44 +0000626void WasmObjectWriter::writeTableSection(uint32_t NumElements) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000627 // For now, always emit the table section, since indirect calls are not
628 // valid without it. In the future, we could perhaps be more clever and omit
629 // it if there are no indirect calls.
Sam Cleggd99f6072017-06-12 23:52:44 +0000630
Sam Clegg9e15f352017-06-03 02:01:24 +0000631 SectionBookkeeping Section;
632 startSection(Section, wasm::WASM_SEC_TABLE);
633
Sam Cleggd99f6072017-06-12 23:52:44 +0000634 encodeULEB128(1, getStream()); // The number of tables.
635 // Fixed to 1 for now.
636 encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream()); // Type of table
637 encodeULEB128(0, getStream()); // flags
638 encodeULEB128(NumElements, getStream()); // initial
Sam Clegg9e15f352017-06-03 02:01:24 +0000639
640 endSection(Section);
641}
642
643void WasmObjectWriter::writeMemorySection(
644 const SmallVector<char, 0> &DataBytes) {
645 // For now, always emit the memory section, since loads and stores are not
646 // valid without it. In the future, we could perhaps be more clever and omit
647 // it if there are no loads or stores.
648 SectionBookkeeping Section;
649 uint32_t NumPages =
650 (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
651
652 startSection(Section, wasm::WASM_SEC_MEMORY);
653 encodeULEB128(1, getStream()); // number of memory spaces
654
655 encodeULEB128(0, getStream()); // flags
656 encodeULEB128(NumPages, getStream()); // initial
657
658 endSection(Section);
659}
660
661void WasmObjectWriter::writeGlobalSection(
662 const SmallVector<WasmGlobal, 4> &Globals) {
663 if (Globals.empty())
664 return;
665
666 SectionBookkeeping Section;
667 startSection(Section, wasm::WASM_SEC_GLOBAL);
668
669 encodeULEB128(Globals.size(), getStream());
670 for (const WasmGlobal &Global : Globals) {
671 writeValueType(Global.Type);
672 write8(Global.IsMutable);
673
674 if (Global.HasImport) {
675 assert(Global.InitialValue == 0);
676 write8(wasm::WASM_OPCODE_GET_GLOBAL);
677 encodeULEB128(Global.ImportIndex, getStream());
678 } else {
679 assert(Global.ImportIndex == 0);
680 write8(wasm::WASM_OPCODE_I32_CONST);
681 encodeSLEB128(Global.InitialValue, getStream()); // offset
682 }
683 write8(wasm::WASM_OPCODE_END);
684 }
685
686 endSection(Section);
687}
688
689void WasmObjectWriter::writeExportSection(
690 const SmallVector<WasmExport, 4> &Exports) {
691 if (Exports.empty())
692 return;
693
694 SectionBookkeeping Section;
695 startSection(Section, wasm::WASM_SEC_EXPORT);
696
697 encodeULEB128(Exports.size(), getStream());
698 for (const WasmExport &Export : Exports) {
699 encodeULEB128(Export.FieldName.size(), getStream());
700 writeBytes(Export.FieldName);
701
702 encodeSLEB128(Export.Kind, getStream());
703
704 encodeULEB128(Export.Index, getStream());
705 }
706
707 endSection(Section);
708}
709
710void WasmObjectWriter::writeElemSection(
711 const SmallVector<uint32_t, 4> &TableElems) {
712 if (TableElems.empty())
713 return;
714
715 SectionBookkeeping Section;
716 startSection(Section, wasm::WASM_SEC_ELEM);
717
718 encodeULEB128(1, getStream()); // number of "segments"
719 encodeULEB128(0, getStream()); // the table index
720
721 // init expr for starting offset
722 write8(wasm::WASM_OPCODE_I32_CONST);
723 encodeSLEB128(0, getStream());
724 write8(wasm::WASM_OPCODE_END);
725
726 encodeULEB128(TableElems.size(), getStream());
727 for (uint32_t Elem : TableElems)
728 encodeULEB128(Elem, getStream());
729
730 endSection(Section);
731}
732
733void WasmObjectWriter::writeCodeSection(
734 const MCAssembler &Asm, const MCAsmLayout &Layout,
Sam Clegg9e15f352017-06-03 02:01:24 +0000735 const SmallVector<WasmFunction, 4> &Functions) {
736 if (Functions.empty())
737 return;
738
739 SectionBookkeeping Section;
740 startSection(Section, wasm::WASM_SEC_CODE);
741
742 encodeULEB128(Functions.size(), getStream());
743
744 for (const WasmFunction &Func : Functions) {
745 MCSectionWasm &FuncSection =
746 static_cast<MCSectionWasm &>(Func.Sym->getSection());
747
748 if (Func.Sym->isVariable())
749 report_fatal_error("weak symbols not supported yet");
750
751 if (Func.Sym->getOffset() != 0)
752 report_fatal_error("function sections must contain one function each");
753
754 if (!Func.Sym->getSize())
755 report_fatal_error("function symbols must have a size set with .size");
756
757 int64_t Size = 0;
758 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
759 report_fatal_error(".size expression must be evaluatable");
760
761 encodeULEB128(Size, getStream());
762
763 FuncSection.setSectionOffset(getStream().tell() -
764 Section.ContentsOffset);
765
766 Asm.writeSectionData(&FuncSection, Layout);
767 }
768
Sam Clegg9e15f352017-06-03 02:01:24 +0000769 // Apply fixups.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000770 applyRelocations(CodeRelocations, Section.ContentsOffset);
Sam Clegg9e15f352017-06-03 02:01:24 +0000771
772 endSection(Section);
773}
774
775uint64_t WasmObjectWriter::writeDataSection(
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000776 const SmallVector<char, 0> &DataBytes) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000777 if (DataBytes.empty())
778 return 0;
779
780 SectionBookkeeping Section;
781 startSection(Section, wasm::WASM_SEC_DATA);
782
783 encodeULEB128(1, getStream()); // count
784 encodeULEB128(0, getStream()); // memory index
785 write8(wasm::WASM_OPCODE_I32_CONST);
786 encodeSLEB128(0, getStream()); // offset
787 write8(wasm::WASM_OPCODE_END);
788 encodeULEB128(DataBytes.size(), getStream()); // size
789 uint32_t HeaderSize = getStream().tell() - Section.ContentsOffset;
790 writeBytes(DataBytes); // data
791
792 // Apply fixups.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000793 applyRelocations(DataRelocations, Section.ContentsOffset + HeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +0000794
795 endSection(Section);
796 return HeaderSize;
797}
798
799void WasmObjectWriter::writeNameSection(
800 const SmallVector<WasmFunction, 4> &Functions,
801 const SmallVector<WasmImport, 4> &Imports,
802 unsigned NumFuncImports) {
803 uint32_t TotalFunctions = NumFuncImports + Functions.size();
804 if (TotalFunctions == 0)
805 return;
806
807 SectionBookkeeping Section;
808 startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
809 SectionBookkeeping SubSection;
810 startSection(SubSection, wasm::WASM_NAMES_FUNCTION);
811
812 encodeULEB128(TotalFunctions, getStream());
813 uint32_t Index = 0;
814 for (const WasmImport &Import : Imports) {
815 if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
816 encodeULEB128(Index, getStream());
817 encodeULEB128(Import.FieldName.size(), getStream());
818 writeBytes(Import.FieldName);
819 ++Index;
820 }
821 }
822 for (const WasmFunction &Func : Functions) {
823 encodeULEB128(Index, getStream());
824 encodeULEB128(Func.Sym->getName().size(), getStream());
825 writeBytes(Func.Sym->getName());
826 ++Index;
827 }
828
829 endSection(SubSection);
830 endSection(Section);
831}
832
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000833void WasmObjectWriter::writeCodeRelocSection() {
Sam Clegg9e15f352017-06-03 02:01:24 +0000834 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
835 // for descriptions of the reloc sections.
836
837 if (CodeRelocations.empty())
838 return;
839
840 SectionBookkeeping Section;
841 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
842
843 encodeULEB128(wasm::WASM_SEC_CODE, getStream());
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000844 encodeULEB128(CodeRelocations.size(), getStream());
Sam Clegg9e15f352017-06-03 02:01:24 +0000845
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000846 writeRelocations(CodeRelocations, 0);
Sam Clegg9e15f352017-06-03 02:01:24 +0000847
848 endSection(Section);
849}
850
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000851void WasmObjectWriter::writeDataRelocSection(uint64_t DataSectionHeaderSize) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000852 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
853 // for descriptions of the reloc sections.
854
855 if (DataRelocations.empty())
856 return;
857
858 SectionBookkeeping Section;
859 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
860
861 encodeULEB128(wasm::WASM_SEC_DATA, getStream());
862 encodeULEB128(DataRelocations.size(), getStream());
863
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000864 writeRelocations(DataRelocations, DataSectionHeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +0000865
866 endSection(Section);
867}
868
869void WasmObjectWriter::writeLinkingMetaDataSection(
870 bool HasStackPointer, uint32_t StackPointerGlobal) {
871 if (!HasStackPointer)
872 return;
873 SectionBookkeeping Section;
874 startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
875
876 encodeULEB128(1, getStream()); // count
877
878 encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type
879 encodeULEB128(StackPointerGlobal, getStream()); // id
880
881 endSection(Section);
882}
883
Dan Gohman18eafb62017-02-22 01:23:18 +0000884void WasmObjectWriter::writeObject(MCAssembler &Asm,
885 const MCAsmLayout &Layout) {
Dan Gohman82607f52017-02-24 23:46:05 +0000886 MCContext &Ctx = Asm.getContext();
Derek Schuffb8795392017-03-16 20:49:48 +0000887 wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32;
Dan Gohmand934cb82017-02-24 23:18:00 +0000888
889 // Collect information from the available symbols.
Dan Gohmand934cb82017-02-24 23:18:00 +0000890 SmallVector<WasmFunctionType, 4> FunctionTypes;
891 SmallVector<WasmFunction, 4> Functions;
892 SmallVector<uint32_t, 4> TableElems;
893 SmallVector<WasmGlobal, 4> Globals;
894 SmallVector<WasmImport, 4> Imports;
895 SmallVector<WasmExport, 4> Exports;
Dan Gohmand934cb82017-02-24 23:18:00 +0000896 SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken;
897 unsigned NumFuncImports = 0;
898 unsigned NumGlobalImports = 0;
899 SmallVector<char, 0> DataBytes;
Dan Gohman970d02c2017-03-30 23:58:19 +0000900 uint32_t StackPointerGlobal = 0;
901 bool HasStackPointer = false;
Dan Gohmand934cb82017-02-24 23:18:00 +0000902
903 // Populate the IsAddressTaken set.
904 for (WasmRelocationEntry RelEntry : CodeRelocations) {
905 switch (RelEntry.Type) {
906 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
907 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
908 IsAddressTaken.insert(RelEntry.Symbol);
909 break;
910 default:
911 break;
912 }
913 }
914 for (WasmRelocationEntry RelEntry : DataRelocations) {
915 switch (RelEntry.Type) {
916 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
917 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
918 IsAddressTaken.insert(RelEntry.Symbol);
919 break;
920 default:
921 break;
922 }
923 }
924
925 // Populate the Imports set.
926 for (const MCSymbol &S : Asm.symbols()) {
927 const auto &WS = static_cast<const MCSymbolWasm &>(S);
Derek Schuffb8795392017-03-16 20:49:48 +0000928 int32_t Type;
Dan Gohmand934cb82017-02-24 23:18:00 +0000929
930 if (WS.isFunction()) {
931 // Prepare the function's type, if we haven't seen it yet.
932 WasmFunctionType F;
933 F.Returns = WS.getReturns();
934 F.Params = WS.getParams();
935 auto Pair =
936 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
937 if (Pair.second)
938 FunctionTypes.push_back(F);
939
940 Type = Pair.first->second;
941 } else {
Derek Schuffb8795392017-03-16 20:49:48 +0000942 Type = int32_t(PtrType);
Dan Gohmand934cb82017-02-24 23:18:00 +0000943 }
944
945 // If the symbol is not defined in this translation unit, import it.
946 if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) {
947 WasmImport Import;
948 Import.ModuleName = WS.getModuleName();
949 Import.FieldName = WS.getName();
950
951 if (WS.isFunction()) {
952 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
953 Import.Type = Type;
954 SymbolIndices[&WS] = NumFuncImports;
955 ++NumFuncImports;
956 } else {
957 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
958 Import.Type = Type;
959 SymbolIndices[&WS] = NumGlobalImports;
960 ++NumGlobalImports;
961 }
962
963 Imports.push_back(Import);
964 }
965 }
966
Dan Gohman82607f52017-02-24 23:46:05 +0000967 // In the special .global_variables section, we've encoded global
968 // variables used by the function. Translate them into the Globals
969 // list.
970 MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0);
971 if (!GlobalVars->getFragmentList().empty()) {
972 if (GlobalVars->getFragmentList().size() != 1)
973 report_fatal_error("only one .global_variables fragment supported");
974 const MCFragment &Frag = *GlobalVars->begin();
975 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
976 report_fatal_error("only data supported in .global_variables");
977 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
978 if (!DataFrag.getFixups().empty())
979 report_fatal_error("fixups not supported in .global_variables");
980 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
Dan Gohman970d02c2017-03-30 23:58:19 +0000981 for (const uint8_t *p = (const uint8_t *)Contents.data(),
982 *end = (const uint8_t *)Contents.data() + Contents.size();
983 p != end; ) {
Dan Gohman82607f52017-02-24 23:46:05 +0000984 WasmGlobal G;
Dan Gohman970d02c2017-03-30 23:58:19 +0000985 if (end - p < 3)
986 report_fatal_error("truncated global variable encoding");
987 G.Type = wasm::ValType(int8_t(*p++));
988 G.IsMutable = bool(*p++);
989 G.HasImport = bool(*p++);
990 if (G.HasImport) {
991 G.InitialValue = 0;
992
993 WasmImport Import;
994 Import.ModuleName = (const char *)p;
995 const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p);
996 if (!nul)
997 report_fatal_error("global module name must be nul-terminated");
998 p = nul + 1;
999 nul = (const uint8_t *)memchr(p, '\0', end - p);
1000 if (!nul)
1001 report_fatal_error("global base name must be nul-terminated");
1002 Import.FieldName = (const char *)p;
1003 p = nul + 1;
1004
1005 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1006 Import.Type = int32_t(G.Type);
1007
1008 G.ImportIndex = NumGlobalImports;
1009 ++NumGlobalImports;
1010
1011 Imports.push_back(Import);
1012 } else {
1013 unsigned n;
1014 G.InitialValue = decodeSLEB128(p, &n);
1015 G.ImportIndex = 0;
Simon Pilgrimc8da0c02017-03-31 10:45:35 +00001016 if ((ptrdiff_t)n > end - p)
Dan Gohman970d02c2017-03-30 23:58:19 +00001017 report_fatal_error("global initial value must be valid SLEB128");
1018 p += n;
1019 }
Dan Gohman82607f52017-02-24 23:46:05 +00001020 Globals.push_back(G);
1021 }
1022 }
1023
Dan Gohman970d02c2017-03-30 23:58:19 +00001024 // In the special .stack_pointer section, we've encoded the stack pointer
1025 // index.
1026 MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0);
1027 if (!StackPtr->getFragmentList().empty()) {
1028 if (StackPtr->getFragmentList().size() != 1)
1029 report_fatal_error("only one .stack_pointer fragment supported");
1030 const MCFragment &Frag = *StackPtr->begin();
1031 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1032 report_fatal_error("only data supported in .stack_pointer");
1033 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1034 if (!DataFrag.getFixups().empty())
1035 report_fatal_error("fixups not supported in .stack_pointer");
1036 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1037 if (Contents.size() != 4)
1038 report_fatal_error("only one entry supported in .stack_pointer");
1039 HasStackPointer = true;
1040 StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data();
1041 }
1042
Dan Gohmand934cb82017-02-24 23:18:00 +00001043 // Handle defined symbols.
1044 for (const MCSymbol &S : Asm.symbols()) {
1045 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1046 // or used in relocations.
1047 if (S.isTemporary() && S.getName().empty())
1048 continue;
1049 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1050 unsigned Index;
1051 if (WS.isFunction()) {
1052 // Prepare the function's type, if we haven't seen it yet.
1053 WasmFunctionType F;
1054 F.Returns = WS.getReturns();
1055 F.Params = WS.getParams();
1056 auto Pair =
1057 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
1058 if (Pair.second)
1059 FunctionTypes.push_back(F);
1060
Derek Schuffb8795392017-03-16 20:49:48 +00001061 int32_t Type = Pair.first->second;
Dan Gohmand934cb82017-02-24 23:18:00 +00001062
1063 if (WS.isDefined(/*SetUsed=*/false)) {
1064 // A definition. Take the next available index.
1065 Index = NumFuncImports + Functions.size();
1066
1067 // Prepare the function.
1068 WasmFunction Func;
1069 Func.Type = Type;
1070 Func.Sym = &WS;
1071 SymbolIndices[&WS] = Index;
1072 Functions.push_back(Func);
1073 } else {
1074 // An import; the index was assigned above.
1075 Index = SymbolIndices.find(&WS)->second;
1076 }
1077
1078 // If needed, prepare the function to be called indirectly.
Sam Cleggd99f6072017-06-12 23:52:44 +00001079 if (IsAddressTaken.count(&WS)) {
1080 IndirectSymbolIndices[&WS] = TableElems.size();
Dan Gohmand934cb82017-02-24 23:18:00 +00001081 TableElems.push_back(Index);
Sam Cleggd99f6072017-06-12 23:52:44 +00001082 }
Dan Gohmand934cb82017-02-24 23:18:00 +00001083 } else {
Sam Cleggc38e9472017-06-02 01:05:24 +00001084 if (WS.isTemporary() && !WS.getSize())
1085 continue;
Dan Gohmand934cb82017-02-24 23:18:00 +00001086
1087 if (WS.isDefined(false)) {
Sam Cleggc38e9472017-06-02 01:05:24 +00001088 if (WS.getOffset() != 0)
1089 report_fatal_error("data sections must contain one variable each: " +
1090 WS.getName());
1091 if (!WS.getSize())
1092 report_fatal_error("data symbols must have a size set with .size: " +
1093 WS.getName());
1094
1095 int64_t Size = 0;
1096 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
1097 report_fatal_error(".size expression must be evaluatable");
1098
Dan Gohmand934cb82017-02-24 23:18:00 +00001099 MCSectionWasm &DataSection =
1100 static_cast<MCSectionWasm &>(WS.getSection());
1101
1102 if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection))
1103 report_fatal_error("data sections must contain at most one variable");
1104
1105 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
1106
1107 DataSection.setSectionOffset(DataBytes.size());
1108
1109 for (MCSection::iterator I = DataSection.begin(), E = DataSection.end();
1110 I != E; ++I) {
1111 const MCFragment &Frag = *I;
1112 if (Frag.hasInstructions())
1113 report_fatal_error("only data supported in data sections");
1114
1115 if (const MCAlignFragment *Align = dyn_cast<MCAlignFragment>(&Frag)) {
1116 if (Align->getValueSize() != 1)
1117 report_fatal_error("only byte values supported for alignment");
1118 // If nops are requested, use zeros, as this is the data section.
1119 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
1120 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
1121 Align->getAlignment()),
1122 DataBytes.size() +
1123 Align->getMaxBytesToEmit());
1124 DataBytes.resize(Size, Value);
1125 } else if (const MCFillFragment *Fill =
1126 dyn_cast<MCFillFragment>(&Frag)) {
1127 DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
1128 } else {
1129 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1130 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1131
1132 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
1133 }
1134 }
1135
Sam Clegg1c154a62017-05-25 21:08:07 +00001136 // For each global, prepare a corresponding wasm global holding its
1137 // address. For externals these will also be named exports.
1138 Index = NumGlobalImports + Globals.size();
Dan Gohmand934cb82017-02-24 23:18:00 +00001139
Sam Clegg1c154a62017-05-25 21:08:07 +00001140 WasmGlobal Global;
1141 Global.Type = PtrType;
1142 Global.IsMutable = false;
1143 Global.HasImport = false;
1144 Global.InitialValue = DataSection.getSectionOffset();
1145 Global.ImportIndex = 0;
1146 SymbolIndices[&WS] = Index;
1147 Globals.push_back(Global);
Dan Gohmand934cb82017-02-24 23:18:00 +00001148 }
1149 }
1150
1151 // If the symbol is visible outside this translation unit, export it.
1152 if (WS.isExternal()) {
1153 assert(WS.isDefined(false));
1154 WasmExport Export;
1155 Export.FieldName = WS.getName();
1156 Export.Index = Index;
1157
1158 if (WS.isFunction())
1159 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1160 else
1161 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1162
1163 Exports.push_back(Export);
1164 }
1165 }
1166
1167 // Add types for indirect function calls.
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001168 for (const WasmRelocationEntry &Fixup : CodeRelocations) {
1169 if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
1170 continue;
Dan Gohman970d02c2017-03-30 23:58:19 +00001171
Dan Gohmand934cb82017-02-24 23:18:00 +00001172 WasmFunctionType F;
1173 F.Returns = Fixup.Symbol->getReturns();
1174 F.Params = Fixup.Symbol->getParams();
1175 auto Pair =
1176 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
1177 if (Pair.second)
1178 FunctionTypes.push_back(F);
1179
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001180 TypeIndices[Fixup.Symbol] = Pair.first->second;
Dan Gohmand934cb82017-02-24 23:18:00 +00001181 }
1182
Dan Gohman18eafb62017-02-22 01:23:18 +00001183 // Write out the Wasm header.
1184 writeHeader(Asm);
1185
Sam Clegg9e15f352017-06-03 02:01:24 +00001186 writeTypeSection(FunctionTypes);
1187 writeImportSection(Imports);
1188 writeFunctionSection(Functions);
Sam Cleggd99f6072017-06-12 23:52:44 +00001189 writeTableSection(TableElems.size());
Sam Clegg9e15f352017-06-03 02:01:24 +00001190 writeMemorySection(DataBytes);
1191 writeGlobalSection(Globals);
1192 writeExportSection(Exports);
1193 // TODO: Start Section
1194 writeElemSection(TableElems);
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001195 writeCodeSection(Asm, Layout, Functions);
1196 uint64_t DataSectionHeaderSize = writeDataSection(DataBytes);
Sam Clegg9e15f352017-06-03 02:01:24 +00001197 writeNameSection(Functions, Imports, NumFuncImports);
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001198 writeCodeRelocSection();
1199 writeDataRelocSection(DataSectionHeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +00001200 writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal);
Dan Gohman970d02c2017-03-30 23:58:19 +00001201
Dan Gohmand934cb82017-02-24 23:18:00 +00001202 // TODO: Translate the .comment section to the output.
Dan Gohmand934cb82017-02-24 23:18:00 +00001203 // TODO: Translate debug sections to the output.
Dan Gohman18eafb62017-02-22 01:23:18 +00001204}
1205
1206MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW,
1207 raw_pwrite_stream &OS) {
1208 return new WasmObjectWriter(MOTW, OS);
1209}