blob: 5f36a9ecce9121d7d8a068650fbb2a5a72e81549 [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"
Dan Gohman18eafb62017-02-22 01:23:18 +000016#include "llvm/MC/MCAsmBackend.h"
17#include "llvm/MC/MCAsmInfo.h"
18#include "llvm/MC/MCAsmLayout.h"
19#include "llvm/MC/MCAssembler.h"
20#include "llvm/MC/MCContext.h"
21#include "llvm/MC/MCExpr.h"
22#include "llvm/MC/MCFixupKindInfo.h"
23#include "llvm/MC/MCObjectFileInfo.h"
24#include "llvm/MC/MCObjectWriter.h"
25#include "llvm/MC/MCSectionWasm.h"
26#include "llvm/MC/MCSymbolWasm.h"
27#include "llvm/MC/MCValue.h"
28#include "llvm/MC/MCWasmObjectWriter.h"
Dan Gohmand934cb82017-02-24 23:18:00 +000029#include "llvm/Support/Casting.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000030#include "llvm/Support/Debug.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000031#include "llvm/Support/ErrorHandling.h"
Dan Gohmand934cb82017-02-24 23:18:00 +000032#include "llvm/Support/LEB128.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000033#include "llvm/Support/StringSaver.h"
34#include <vector>
35
36using namespace llvm;
37
38#undef DEBUG_TYPE
39#define DEBUG_TYPE "reloc-info"
40
41namespace {
Sam Clegg9e15f352017-06-03 02:01:24 +000042
Dan Gohmand934cb82017-02-24 23:18:00 +000043// For patching purposes, we need to remember where each section starts, both
44// for patching up the section size field, and for patching up references to
45// locations within the section.
46struct SectionBookkeeping {
47 // Where the size of the section is written.
48 uint64_t SizeOffset;
49 // Where the contents of the section starts (after the header).
50 uint64_t ContentsOffset;
51};
52
Sam Clegg9e15f352017-06-03 02:01:24 +000053// The signature of a wasm function, in a struct capable of being used as a
54// DenseMap key.
55struct WasmFunctionType {
56 // Support empty and tombstone instances, needed by DenseMap.
57 enum { Plain, Empty, Tombstone } State;
58
59 // The return types of the function.
60 SmallVector<wasm::ValType, 1> Returns;
61
62 // The parameter types of the function.
63 SmallVector<wasm::ValType, 4> Params;
64
65 WasmFunctionType() : State(Plain) {}
66
67 bool operator==(const WasmFunctionType &Other) const {
68 return State == Other.State && Returns == Other.Returns &&
69 Params == Other.Params;
70 }
71};
72
73// Traits for using WasmFunctionType in a DenseMap.
74struct WasmFunctionTypeDenseMapInfo {
75 static WasmFunctionType getEmptyKey() {
76 WasmFunctionType FuncTy;
77 FuncTy.State = WasmFunctionType::Empty;
78 return FuncTy;
79 }
80 static WasmFunctionType getTombstoneKey() {
81 WasmFunctionType FuncTy;
82 FuncTy.State = WasmFunctionType::Tombstone;
83 return FuncTy;
84 }
85 static unsigned getHashValue(const WasmFunctionType &FuncTy) {
86 uintptr_t Value = FuncTy.State;
87 for (wasm::ValType Ret : FuncTy.Returns)
88 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret));
89 for (wasm::ValType Param : FuncTy.Params)
90 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param));
91 return Value;
92 }
93 static bool isEqual(const WasmFunctionType &LHS,
94 const WasmFunctionType &RHS) {
95 return LHS == RHS;
96 }
97};
98
99// A wasm import to be written into the import section.
100struct WasmImport {
101 StringRef ModuleName;
102 StringRef FieldName;
103 unsigned Kind;
104 int32_t Type;
105};
106
107// A wasm function to be written into the function section.
108struct WasmFunction {
109 int32_t Type;
110 const MCSymbolWasm *Sym;
111};
112
113// A wasm export to be written into the export section.
114struct WasmExport {
115 StringRef FieldName;
116 unsigned Kind;
117 uint32_t Index;
118};
119
120// A wasm global to be written into the global section.
121struct WasmGlobal {
122 wasm::ValType Type;
123 bool IsMutable;
124 bool HasImport;
125 uint64_t InitialValue;
126 uint32_t ImportIndex;
127};
128
Sam Clegg6dc65e92017-06-06 16:38:59 +0000129// Information about a single relocation.
130struct WasmRelocationEntry {
131 uint64_t Offset; // Where is the relocation.
132 const MCSymbolWasm *Symbol; // The symbol to relocate with.
133 int64_t Addend; // A value to add to the symbol.
134 unsigned Type; // The type of the relocation.
135 MCSectionWasm *FixupSection;// The section the relocation is targeting.
136
137 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
138 int64_t Addend, unsigned Type,
139 MCSectionWasm *FixupSection)
140 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
141 FixupSection(FixupSection) {}
142
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000143 bool hasAddend() const {
144 switch (Type) {
145 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
146 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
147 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
148 return true;
149 default:
150 return false;
151 }
152 }
153
Sam Clegg6dc65e92017-06-06 16:38:59 +0000154 void print(raw_ostream &Out) const {
155 Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend
156 << ", Type=" << Type << ", FixupSection=" << FixupSection;
157 }
158 void dump() const { print(errs()); }
159};
160
Dan Gohman18eafb62017-02-22 01:23:18 +0000161class WasmObjectWriter : public MCObjectWriter {
162 /// Helper struct for containing some precomputed information on symbols.
163 struct WasmSymbolData {
164 const MCSymbolWasm *Symbol;
165 StringRef Name;
166
167 // Support lexicographic sorting.
168 bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; }
169 };
170
171 /// The target specific Wasm writer instance.
172 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
173
Dan Gohmand934cb82017-02-24 23:18:00 +0000174 // Relocations for fixing up references in the code section.
175 std::vector<WasmRelocationEntry> CodeRelocations;
176
177 // Relocations for fixing up references in the data section.
178 std::vector<WasmRelocationEntry> DataRelocations;
179
Dan Gohmand934cb82017-02-24 23:18:00 +0000180 // Index values to use for fixing up call_indirect type indices.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000181 // Maps function symbols to the index of the type of the function
182 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
183
184 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices;
185
186 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo>
187 FunctionTypeIndices;
Dan Gohmand934cb82017-02-24 23:18:00 +0000188
Dan Gohman18eafb62017-02-22 01:23:18 +0000189 // TargetObjectWriter wrappers.
190 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
191 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
192 const MCFixup &Fixup, bool IsPCRel) const {
193 return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
194 }
195
Dan Gohmand934cb82017-02-24 23:18:00 +0000196 void startSection(SectionBookkeeping &Section, unsigned SectionId,
197 const char *Name = nullptr);
198 void endSection(SectionBookkeeping &Section);
199
Dan Gohman18eafb62017-02-22 01:23:18 +0000200public:
201 WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS)
202 : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {}
203
Dan Gohmand934cb82017-02-24 23:18:00 +0000204private:
Dan Gohman18eafb62017-02-22 01:23:18 +0000205 ~WasmObjectWriter() override;
206
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000207 void reset() override {
208 CodeRelocations.clear();
209 DataRelocations.clear();
210 TypeIndices.clear();
211 SymbolIndices.clear();
212 FunctionTypeIndices.clear();
213 MCObjectWriter::reset();
214 }
215
Dan Gohman18eafb62017-02-22 01:23:18 +0000216 void writeHeader(const MCAssembler &Asm);
217
218 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
219 const MCFragment *Fragment, const MCFixup &Fixup,
220 MCValue Target, bool &IsPCRel,
221 uint64_t &FixedValue) override;
222
223 void executePostLayoutBinding(MCAssembler &Asm,
224 const MCAsmLayout &Layout) override;
225
226 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
Sam Clegg9e15f352017-06-03 02:01:24 +0000227
228 void writeValueType(wasm::ValType Ty) {
229 encodeSLEB128(int32_t(Ty), getStream());
230 }
231
232 void writeTypeSection(const SmallVector<WasmFunctionType, 4> &FunctionTypes);
233 void writeImportSection(const SmallVector<WasmImport, 4> &Imports);
234 void writeFunctionSection(const SmallVector<WasmFunction, 4> &Functions);
235 void writeTableSection(const SmallVector<uint32_t, 4> &TableElems);
236 void writeMemorySection(const SmallVector<char, 0> &DataBytes);
237 void writeGlobalSection(const SmallVector<WasmGlobal, 4> &Globals);
238 void writeExportSection(const SmallVector<WasmExport, 4> &Exports);
239 void writeElemSection(const SmallVector<uint32_t, 4> &TableElems);
240 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
Sam Clegg9e15f352017-06-03 02:01:24 +0000241 const SmallVector<WasmFunction, 4> &Functions);
242 uint64_t
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000243 writeDataSection(const SmallVector<char, 0> &DataBytes);
Sam Clegg9e15f352017-06-03 02:01:24 +0000244 void writeNameSection(const SmallVector<WasmFunction, 4> &Functions,
245 const SmallVector<WasmImport, 4> &Imports,
246 uint32_t NumFuncImports);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000247 void writeCodeRelocSection();
248 void writeDataRelocSection(uint64_t DataSectionHeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +0000249 void writeLinkingMetaDataSection(bool HasStackPointer,
250 uint32_t StackPointerGlobal);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000251
252 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
253 uint64_t ContentsOffset);
254
255 void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations,
256 uint64_t HeaderSize);
257 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
Dan Gohman18eafb62017-02-22 01:23:18 +0000258};
Sam Clegg9e15f352017-06-03 02:01:24 +0000259
Dan Gohman18eafb62017-02-22 01:23:18 +0000260} // end anonymous namespace
261
262WasmObjectWriter::~WasmObjectWriter() {}
263
Dan Gohmand934cb82017-02-24 23:18:00 +0000264// Return the padding size to write a 32-bit value into a 5-byte ULEB128.
265static unsigned PaddingFor5ByteULEB128(uint32_t X) {
266 return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u);
267}
268
269// Return the padding size to write a 32-bit value into a 5-byte SLEB128.
270static unsigned PaddingFor5ByteSLEB128(int32_t X) {
271 return 5 - getSLEB128Size(X);
272}
273
274// Write out a section header and a patchable section size field.
275void WasmObjectWriter::startSection(SectionBookkeeping &Section,
276 unsigned SectionId,
277 const char *Name) {
278 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) &&
279 "Only custom sections can have names");
280
Derek Schuffe2688c42017-03-14 20:23:22 +0000281 encodeULEB128(SectionId, getStream());
Dan Gohmand934cb82017-02-24 23:18:00 +0000282
283 Section.SizeOffset = getStream().tell();
284
285 // The section size. We don't know the size yet, so reserve enough space
286 // for any 32-bit value; we'll patch it later.
287 encodeULEB128(UINT32_MAX, getStream());
288
289 // The position where the section starts, for measuring its size.
290 Section.ContentsOffset = getStream().tell();
291
292 // Custom sections in wasm also have a string identifier.
293 if (SectionId == wasm::WASM_SEC_CUSTOM) {
294 encodeULEB128(strlen(Name), getStream());
295 writeBytes(Name);
296 }
297}
298
299// Now that the section is complete and we know how big it is, patch up the
300// section size field at the start of the section.
301void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
302 uint64_t Size = getStream().tell() - Section.ContentsOffset;
303 if (uint32_t(Size) != Size)
304 report_fatal_error("section size does not fit in a uint32_t");
305
306 unsigned Padding = PaddingFor5ByteULEB128(Size);
307
308 // Write the final section size to the payload_len field, which follows
309 // the section id byte.
310 uint8_t Buffer[16];
311 unsigned SizeLen = encodeULEB128(Size, Buffer, Padding);
312 assert(SizeLen == 5);
313 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
314}
315
Dan Gohman18eafb62017-02-22 01:23:18 +0000316// Emit the Wasm header.
317void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
Dan Gohman7ea5adf2017-02-22 18:50:20 +0000318 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic)));
319 writeLE32(wasm::WasmVersion);
Dan Gohman18eafb62017-02-22 01:23:18 +0000320}
321
322void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
323 const MCAsmLayout &Layout) {
324}
325
326void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
327 const MCAsmLayout &Layout,
328 const MCFragment *Fragment,
329 const MCFixup &Fixup, MCValue Target,
330 bool &IsPCRel, uint64_t &FixedValue) {
Dan Gohmand934cb82017-02-24 23:18:00 +0000331 MCSectionWasm &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
332 uint64_t C = Target.getConstant();
333 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
334 MCContext &Ctx = Asm.getContext();
335
336 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
337 assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
338 "Should not have constructed this");
339
340 // Let A, B and C being the components of Target and R be the location of
341 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
342 // If it is pcrel, we want to compute (A - B + C - R).
343
344 // In general, Wasm has no relocations for -B. It can only represent (A + C)
345 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
346 // replace B to implement it: (A - R - K + C)
347 if (IsPCRel) {
348 Ctx.reportError(
349 Fixup.getLoc(),
350 "No relocation available to represent this relative expression");
351 return;
352 }
353
354 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
355
356 if (SymB.isUndefined()) {
357 Ctx.reportError(Fixup.getLoc(),
358 Twine("symbol '") + SymB.getName() +
359 "' can not be undefined in a subtraction expression");
360 return;
361 }
362
363 assert(!SymB.isAbsolute() && "Should have been folded");
364 const MCSection &SecB = SymB.getSection();
365 if (&SecB != &FixupSection) {
366 Ctx.reportError(Fixup.getLoc(),
367 "Cannot represent a difference across sections");
368 return;
369 }
370
371 uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
372 uint64_t K = SymBOffset - FixupOffset;
373 IsPCRel = true;
374 C -= K;
375 }
376
377 // We either rejected the fixup or folded B into C at this point.
378 const MCSymbolRefExpr *RefA = Target.getSymA();
379 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
380
381 bool ViaWeakRef = false;
382 if (SymA && SymA->isVariable()) {
383 const MCExpr *Expr = SymA->getVariableValue();
384 if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
385 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
386 SymA = cast<MCSymbolWasm>(&Inner->getSymbol());
387 ViaWeakRef = true;
388 }
389 }
390 }
391
392 // Put any constant offset in an addend. Offsets can be negative, and
393 // LLVM expects wrapping, in contrast to wasm's immediates which can't
394 // be negative and don't wrap.
395 FixedValue = 0;
396
397 if (SymA) {
398 if (ViaWeakRef)
399 llvm_unreachable("weakref used in reloc not yet implemented");
400 else
401 SymA->setUsedInReloc();
402 }
403
Dan Gohmand934cb82017-02-24 23:18:00 +0000404 unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel);
Dan Gohmand934cb82017-02-24 23:18:00 +0000405 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
406
407 if (FixupSection.hasInstructions())
408 CodeRelocations.push_back(Rec);
409 else
410 DataRelocations.push_back(Rec);
411}
412
Dan Gohmand934cb82017-02-24 23:18:00 +0000413// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
414// to allow patching.
415static void
416WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
417 uint8_t Buffer[5];
418 unsigned Padding = PaddingFor5ByteULEB128(X);
419 unsigned SizeLen = encodeULEB128(X, Buffer, Padding);
420 assert(SizeLen == 5);
421 Stream.pwrite((char *)Buffer, SizeLen, Offset);
422}
423
424// Write X as an signed LEB value at offset Offset in Stream, padded
425// to allow patching.
426static void
427WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
428 uint8_t Buffer[5];
429 unsigned Padding = PaddingFor5ByteSLEB128(X);
430 unsigned SizeLen = encodeSLEB128(X, Buffer, Padding);
431 assert(SizeLen == 5);
432 Stream.pwrite((char *)Buffer, SizeLen, Offset);
433}
434
435// Write X as a plain integer value at offset Offset in Stream.
436static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
437 uint8_t Buffer[4];
438 support::endian::write32le(Buffer, X);
439 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
440}
441
442// Compute a value to write into the code at the location covered
443// by RelEntry. This value isn't used by the static linker, since
444// we have addends; it just serves to make the code more readable
445// and to make standalone wasm modules directly usable.
446static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) {
447 const MCSymbolWasm *Sym = RelEntry.Symbol;
448
449 // For undefined symbols, use a hopefully invalid value.
450 if (!Sym->isDefined(false))
451 return UINT32_MAX;
452
453 MCSectionWasm &Section =
454 cast<MCSectionWasm>(RelEntry.Symbol->getSection(false));
455 uint64_t Address = Section.getSectionOffset() + RelEntry.Addend;
456
457 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
458 uint32_t Value = Address;
459
460 return Value;
461}
462
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000463uint32_t WasmObjectWriter::getRelocationIndexValue(
464 const WasmRelocationEntry &RelEntry) {
465 switch (RelEntry.Type) {
466 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
467 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
468 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
469 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
470 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
471 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
472 assert(SymbolIndices.count(RelEntry.Symbol));
473 return SymbolIndices[RelEntry.Symbol];
474 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
475 assert(TypeIndices.count(RelEntry.Symbol));
476 return TypeIndices[RelEntry.Symbol];
477 default:
478 llvm_unreachable("invalid relocation type");
479 }
480}
481
Dan Gohmand934cb82017-02-24 23:18:00 +0000482// Apply the portions of the relocation records that we can handle ourselves
483// directly.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000484void WasmObjectWriter::applyRelocations(
485 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
486 raw_pwrite_stream &Stream = getStream();
Dan Gohmand934cb82017-02-24 23:18:00 +0000487 for (const WasmRelocationEntry &RelEntry : Relocations) {
488 uint64_t Offset = ContentsOffset +
489 RelEntry.FixupSection->getSectionOffset() +
490 RelEntry.Offset;
Dan Gohmand934cb82017-02-24 23:18:00 +0000491
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000492 switch (RelEntry.Type) {
493 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
494 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
495 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: {
496 uint32_t Index = getRelocationIndexValue(RelEntry);
497 WritePatchableSLEB(Stream, Index, Offset);
Dan Gohmand934cb82017-02-24 23:18:00 +0000498 break;
499 }
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000500 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
501 uint32_t Index = getRelocationIndexValue(RelEntry);
502 WriteI32(Stream, Index, Offset);
Dan Gohmand934cb82017-02-24 23:18:00 +0000503 break;
504 }
505 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: {
506 uint32_t Value = ProvisionalValue(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +0000507 WritePatchableSLEB(Stream, Value, Offset);
508 break;
509 }
510 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: {
511 uint32_t Value = ProvisionalValue(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +0000512 WritePatchableLEB(Stream, Value, Offset);
513 break;
514 }
Dan Gohmand934cb82017-02-24 23:18:00 +0000515 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: {
516 uint32_t Value = ProvisionalValue(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +0000517 WriteI32(Stream, Value, Offset);
518 break;
519 }
520 default:
Dan Gohmand934cb82017-02-24 23:18:00 +0000521 llvm_unreachable("unsupported relocation type");
522 }
523 }
Dan Gohman18eafb62017-02-22 01:23:18 +0000524}
525
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000526// Write out the portions of the relocation records that the linker will
Dan Gohman970d02c2017-03-30 23:58:19 +0000527// need to handle.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000528void WasmObjectWriter::writeRelocations(
529 ArrayRef<WasmRelocationEntry> Relocations, uint64_t HeaderSize) {
530 raw_pwrite_stream &Stream = getStream();
531 for (const WasmRelocationEntry& RelEntry : Relocations) {
Dan Gohman970d02c2017-03-30 23:58:19 +0000532
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000533 uint64_t Offset = RelEntry.Offset +
534 RelEntry.FixupSection->getSectionOffset() + HeaderSize;
535 uint32_t Index = getRelocationIndexValue(RelEntry);
Dan Gohman970d02c2017-03-30 23:58:19 +0000536
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000537 encodeULEB128(RelEntry.Type, Stream);
Dan Gohman970d02c2017-03-30 23:58:19 +0000538 encodeULEB128(Offset, Stream);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000539 encodeULEB128(Index, Stream);
540 if (RelEntry.hasAddend())
541 encodeSLEB128(RelEntry.Addend, Stream);
Dan Gohman970d02c2017-03-30 23:58:19 +0000542 }
543}
544
Sam Clegg9e15f352017-06-03 02:01:24 +0000545void WasmObjectWriter::writeTypeSection(
546 const SmallVector<WasmFunctionType, 4> &FunctionTypes) {
547 if (FunctionTypes.empty())
548 return;
549
550 SectionBookkeeping Section;
551 startSection(Section, wasm::WASM_SEC_TYPE);
552
553 encodeULEB128(FunctionTypes.size(), getStream());
554
555 for (const WasmFunctionType &FuncTy : FunctionTypes) {
556 encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream());
557 encodeULEB128(FuncTy.Params.size(), getStream());
558 for (wasm::ValType Ty : FuncTy.Params)
559 writeValueType(Ty);
560 encodeULEB128(FuncTy.Returns.size(), getStream());
561 for (wasm::ValType Ty : FuncTy.Returns)
562 writeValueType(Ty);
563 }
564
565 endSection(Section);
566}
567
568void WasmObjectWriter::writeImportSection(
569 const SmallVector<WasmImport, 4> &Imports) {
570 if (Imports.empty())
571 return;
572
573 SectionBookkeeping Section;
574 startSection(Section, wasm::WASM_SEC_IMPORT);
575
576 encodeULEB128(Imports.size(), getStream());
577 for (const WasmImport &Import : Imports) {
578 StringRef ModuleName = Import.ModuleName;
579 encodeULEB128(ModuleName.size(), getStream());
580 writeBytes(ModuleName);
581
582 StringRef FieldName = Import.FieldName;
583 encodeULEB128(FieldName.size(), getStream());
584 writeBytes(FieldName);
585
586 encodeULEB128(Import.Kind, getStream());
587
588 switch (Import.Kind) {
589 case wasm::WASM_EXTERNAL_FUNCTION:
590 encodeULEB128(Import.Type, getStream());
591 break;
592 case wasm::WASM_EXTERNAL_GLOBAL:
593 encodeSLEB128(int32_t(Import.Type), getStream());
594 encodeULEB128(0, getStream()); // mutability
595 break;
596 default:
597 llvm_unreachable("unsupported import kind");
598 }
599 }
600
601 endSection(Section);
602}
603
604void WasmObjectWriter::writeFunctionSection(
605 const SmallVector<WasmFunction, 4> &Functions) {
606 if (Functions.empty())
607 return;
608
609 SectionBookkeeping Section;
610 startSection(Section, wasm::WASM_SEC_FUNCTION);
611
612 encodeULEB128(Functions.size(), getStream());
613 for (const WasmFunction &Func : Functions)
614 encodeULEB128(Func.Type, getStream());
615
616 endSection(Section);
617}
618
619void WasmObjectWriter::writeTableSection(
620 const SmallVector<uint32_t, 4> &TableElems) {
621 // For now, always emit the table section, since indirect calls are not
622 // valid without it. In the future, we could perhaps be more clever and omit
623 // it if there are no indirect calls.
624 SectionBookkeeping Section;
625 startSection(Section, wasm::WASM_SEC_TABLE);
626
627 // The number of tables, fixed to 1 for now.
628 encodeULEB128(1, getStream());
629
630 encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream());
631
632 encodeULEB128(0, getStream()); // flags
633 encodeULEB128(TableElems.size(), getStream()); // initial
634
635 endSection(Section);
636}
637
638void WasmObjectWriter::writeMemorySection(
639 const SmallVector<char, 0> &DataBytes) {
640 // For now, always emit the memory section, since loads and stores are not
641 // valid without it. In the future, we could perhaps be more clever and omit
642 // it if there are no loads or stores.
643 SectionBookkeeping Section;
644 uint32_t NumPages =
645 (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
646
647 startSection(Section, wasm::WASM_SEC_MEMORY);
648 encodeULEB128(1, getStream()); // number of memory spaces
649
650 encodeULEB128(0, getStream()); // flags
651 encodeULEB128(NumPages, getStream()); // initial
652
653 endSection(Section);
654}
655
656void WasmObjectWriter::writeGlobalSection(
657 const SmallVector<WasmGlobal, 4> &Globals) {
658 if (Globals.empty())
659 return;
660
661 SectionBookkeeping Section;
662 startSection(Section, wasm::WASM_SEC_GLOBAL);
663
664 encodeULEB128(Globals.size(), getStream());
665 for (const WasmGlobal &Global : Globals) {
666 writeValueType(Global.Type);
667 write8(Global.IsMutable);
668
669 if (Global.HasImport) {
670 assert(Global.InitialValue == 0);
671 write8(wasm::WASM_OPCODE_GET_GLOBAL);
672 encodeULEB128(Global.ImportIndex, getStream());
673 } else {
674 assert(Global.ImportIndex == 0);
675 write8(wasm::WASM_OPCODE_I32_CONST);
676 encodeSLEB128(Global.InitialValue, getStream()); // offset
677 }
678 write8(wasm::WASM_OPCODE_END);
679 }
680
681 endSection(Section);
682}
683
684void WasmObjectWriter::writeExportSection(
685 const SmallVector<WasmExport, 4> &Exports) {
686 if (Exports.empty())
687 return;
688
689 SectionBookkeeping Section;
690 startSection(Section, wasm::WASM_SEC_EXPORT);
691
692 encodeULEB128(Exports.size(), getStream());
693 for (const WasmExport &Export : Exports) {
694 encodeULEB128(Export.FieldName.size(), getStream());
695 writeBytes(Export.FieldName);
696
697 encodeSLEB128(Export.Kind, getStream());
698
699 encodeULEB128(Export.Index, getStream());
700 }
701
702 endSection(Section);
703}
704
705void WasmObjectWriter::writeElemSection(
706 const SmallVector<uint32_t, 4> &TableElems) {
707 if (TableElems.empty())
708 return;
709
710 SectionBookkeeping Section;
711 startSection(Section, wasm::WASM_SEC_ELEM);
712
713 encodeULEB128(1, getStream()); // number of "segments"
714 encodeULEB128(0, getStream()); // the table index
715
716 // init expr for starting offset
717 write8(wasm::WASM_OPCODE_I32_CONST);
718 encodeSLEB128(0, getStream());
719 write8(wasm::WASM_OPCODE_END);
720
721 encodeULEB128(TableElems.size(), getStream());
722 for (uint32_t Elem : TableElems)
723 encodeULEB128(Elem, getStream());
724
725 endSection(Section);
726}
727
728void WasmObjectWriter::writeCodeSection(
729 const MCAssembler &Asm, const MCAsmLayout &Layout,
Sam Clegg9e15f352017-06-03 02:01:24 +0000730 const SmallVector<WasmFunction, 4> &Functions) {
731 if (Functions.empty())
732 return;
733
734 SectionBookkeeping Section;
735 startSection(Section, wasm::WASM_SEC_CODE);
736
737 encodeULEB128(Functions.size(), getStream());
738
739 for (const WasmFunction &Func : Functions) {
740 MCSectionWasm &FuncSection =
741 static_cast<MCSectionWasm &>(Func.Sym->getSection());
742
743 if (Func.Sym->isVariable())
744 report_fatal_error("weak symbols not supported yet");
745
746 if (Func.Sym->getOffset() != 0)
747 report_fatal_error("function sections must contain one function each");
748
749 if (!Func.Sym->getSize())
750 report_fatal_error("function symbols must have a size set with .size");
751
752 int64_t Size = 0;
753 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
754 report_fatal_error(".size expression must be evaluatable");
755
756 encodeULEB128(Size, getStream());
757
758 FuncSection.setSectionOffset(getStream().tell() -
759 Section.ContentsOffset);
760
761 Asm.writeSectionData(&FuncSection, Layout);
762 }
763
Sam Clegg9e15f352017-06-03 02:01:24 +0000764 // Apply fixups.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000765 applyRelocations(CodeRelocations, Section.ContentsOffset);
Sam Clegg9e15f352017-06-03 02:01:24 +0000766
767 endSection(Section);
768}
769
770uint64_t WasmObjectWriter::writeDataSection(
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000771 const SmallVector<char, 0> &DataBytes) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000772 if (DataBytes.empty())
773 return 0;
774
775 SectionBookkeeping Section;
776 startSection(Section, wasm::WASM_SEC_DATA);
777
778 encodeULEB128(1, getStream()); // count
779 encodeULEB128(0, getStream()); // memory index
780 write8(wasm::WASM_OPCODE_I32_CONST);
781 encodeSLEB128(0, getStream()); // offset
782 write8(wasm::WASM_OPCODE_END);
783 encodeULEB128(DataBytes.size(), getStream()); // size
784 uint32_t HeaderSize = getStream().tell() - Section.ContentsOffset;
785 writeBytes(DataBytes); // data
786
787 // Apply fixups.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000788 applyRelocations(DataRelocations, Section.ContentsOffset + HeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +0000789
790 endSection(Section);
791 return HeaderSize;
792}
793
794void WasmObjectWriter::writeNameSection(
795 const SmallVector<WasmFunction, 4> &Functions,
796 const SmallVector<WasmImport, 4> &Imports,
797 unsigned NumFuncImports) {
798 uint32_t TotalFunctions = NumFuncImports + Functions.size();
799 if (TotalFunctions == 0)
800 return;
801
802 SectionBookkeeping Section;
803 startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
804 SectionBookkeeping SubSection;
805 startSection(SubSection, wasm::WASM_NAMES_FUNCTION);
806
807 encodeULEB128(TotalFunctions, getStream());
808 uint32_t Index = 0;
809 for (const WasmImport &Import : Imports) {
810 if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
811 encodeULEB128(Index, getStream());
812 encodeULEB128(Import.FieldName.size(), getStream());
813 writeBytes(Import.FieldName);
814 ++Index;
815 }
816 }
817 for (const WasmFunction &Func : Functions) {
818 encodeULEB128(Index, getStream());
819 encodeULEB128(Func.Sym->getName().size(), getStream());
820 writeBytes(Func.Sym->getName());
821 ++Index;
822 }
823
824 endSection(SubSection);
825 endSection(Section);
826}
827
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000828void WasmObjectWriter::writeCodeRelocSection() {
Sam Clegg9e15f352017-06-03 02:01:24 +0000829 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
830 // for descriptions of the reloc sections.
831
832 if (CodeRelocations.empty())
833 return;
834
835 SectionBookkeeping Section;
836 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
837
838 encodeULEB128(wasm::WASM_SEC_CODE, getStream());
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000839 encodeULEB128(CodeRelocations.size(), getStream());
Sam Clegg9e15f352017-06-03 02:01:24 +0000840
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000841 writeRelocations(CodeRelocations, 0);
Sam Clegg9e15f352017-06-03 02:01:24 +0000842
843 endSection(Section);
844}
845
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000846void WasmObjectWriter::writeDataRelocSection(uint64_t DataSectionHeaderSize) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000847 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
848 // for descriptions of the reloc sections.
849
850 if (DataRelocations.empty())
851 return;
852
853 SectionBookkeeping Section;
854 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
855
856 encodeULEB128(wasm::WASM_SEC_DATA, getStream());
857 encodeULEB128(DataRelocations.size(), getStream());
858
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000859 writeRelocations(DataRelocations, DataSectionHeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +0000860
861 endSection(Section);
862}
863
864void WasmObjectWriter::writeLinkingMetaDataSection(
865 bool HasStackPointer, uint32_t StackPointerGlobal) {
866 if (!HasStackPointer)
867 return;
868 SectionBookkeeping Section;
869 startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
870
871 encodeULEB128(1, getStream()); // count
872
873 encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type
874 encodeULEB128(StackPointerGlobal, getStream()); // id
875
876 endSection(Section);
877}
878
Dan Gohman18eafb62017-02-22 01:23:18 +0000879void WasmObjectWriter::writeObject(MCAssembler &Asm,
880 const MCAsmLayout &Layout) {
Dan Gohman82607f52017-02-24 23:46:05 +0000881 MCContext &Ctx = Asm.getContext();
Derek Schuffb8795392017-03-16 20:49:48 +0000882 wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32;
Dan Gohmand934cb82017-02-24 23:18:00 +0000883
884 // Collect information from the available symbols.
Dan Gohmand934cb82017-02-24 23:18:00 +0000885 SmallVector<WasmFunctionType, 4> FunctionTypes;
886 SmallVector<WasmFunction, 4> Functions;
887 SmallVector<uint32_t, 4> TableElems;
888 SmallVector<WasmGlobal, 4> Globals;
889 SmallVector<WasmImport, 4> Imports;
890 SmallVector<WasmExport, 4> Exports;
Dan Gohmand934cb82017-02-24 23:18:00 +0000891 SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken;
892 unsigned NumFuncImports = 0;
893 unsigned NumGlobalImports = 0;
894 SmallVector<char, 0> DataBytes;
Dan Gohman970d02c2017-03-30 23:58:19 +0000895 uint32_t StackPointerGlobal = 0;
896 bool HasStackPointer = false;
Dan Gohmand934cb82017-02-24 23:18:00 +0000897
898 // Populate the IsAddressTaken set.
899 for (WasmRelocationEntry RelEntry : CodeRelocations) {
900 switch (RelEntry.Type) {
901 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
902 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
903 IsAddressTaken.insert(RelEntry.Symbol);
904 break;
905 default:
906 break;
907 }
908 }
909 for (WasmRelocationEntry RelEntry : DataRelocations) {
910 switch (RelEntry.Type) {
911 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
912 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
913 IsAddressTaken.insert(RelEntry.Symbol);
914 break;
915 default:
916 break;
917 }
918 }
919
920 // Populate the Imports set.
921 for (const MCSymbol &S : Asm.symbols()) {
922 const auto &WS = static_cast<const MCSymbolWasm &>(S);
Derek Schuffb8795392017-03-16 20:49:48 +0000923 int32_t Type;
Dan Gohmand934cb82017-02-24 23:18:00 +0000924
925 if (WS.isFunction()) {
926 // Prepare the function's type, if we haven't seen it yet.
927 WasmFunctionType F;
928 F.Returns = WS.getReturns();
929 F.Params = WS.getParams();
930 auto Pair =
931 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
932 if (Pair.second)
933 FunctionTypes.push_back(F);
934
935 Type = Pair.first->second;
936 } else {
Derek Schuffb8795392017-03-16 20:49:48 +0000937 Type = int32_t(PtrType);
Dan Gohmand934cb82017-02-24 23:18:00 +0000938 }
939
940 // If the symbol is not defined in this translation unit, import it.
941 if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) {
942 WasmImport Import;
943 Import.ModuleName = WS.getModuleName();
944 Import.FieldName = WS.getName();
945
946 if (WS.isFunction()) {
947 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
948 Import.Type = Type;
949 SymbolIndices[&WS] = NumFuncImports;
950 ++NumFuncImports;
951 } else {
952 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
953 Import.Type = Type;
954 SymbolIndices[&WS] = NumGlobalImports;
955 ++NumGlobalImports;
956 }
957
958 Imports.push_back(Import);
959 }
960 }
961
Dan Gohman82607f52017-02-24 23:46:05 +0000962 // In the special .global_variables section, we've encoded global
963 // variables used by the function. Translate them into the Globals
964 // list.
965 MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0);
966 if (!GlobalVars->getFragmentList().empty()) {
967 if (GlobalVars->getFragmentList().size() != 1)
968 report_fatal_error("only one .global_variables fragment supported");
969 const MCFragment &Frag = *GlobalVars->begin();
970 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
971 report_fatal_error("only data supported in .global_variables");
972 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
973 if (!DataFrag.getFixups().empty())
974 report_fatal_error("fixups not supported in .global_variables");
975 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
Dan Gohman970d02c2017-03-30 23:58:19 +0000976 for (const uint8_t *p = (const uint8_t *)Contents.data(),
977 *end = (const uint8_t *)Contents.data() + Contents.size();
978 p != end; ) {
Dan Gohman82607f52017-02-24 23:46:05 +0000979 WasmGlobal G;
Dan Gohman970d02c2017-03-30 23:58:19 +0000980 if (end - p < 3)
981 report_fatal_error("truncated global variable encoding");
982 G.Type = wasm::ValType(int8_t(*p++));
983 G.IsMutable = bool(*p++);
984 G.HasImport = bool(*p++);
985 if (G.HasImport) {
986 G.InitialValue = 0;
987
988 WasmImport Import;
989 Import.ModuleName = (const char *)p;
990 const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p);
991 if (!nul)
992 report_fatal_error("global module name must be nul-terminated");
993 p = nul + 1;
994 nul = (const uint8_t *)memchr(p, '\0', end - p);
995 if (!nul)
996 report_fatal_error("global base name must be nul-terminated");
997 Import.FieldName = (const char *)p;
998 p = nul + 1;
999
1000 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1001 Import.Type = int32_t(G.Type);
1002
1003 G.ImportIndex = NumGlobalImports;
1004 ++NumGlobalImports;
1005
1006 Imports.push_back(Import);
1007 } else {
1008 unsigned n;
1009 G.InitialValue = decodeSLEB128(p, &n);
1010 G.ImportIndex = 0;
Simon Pilgrimc8da0c02017-03-31 10:45:35 +00001011 if ((ptrdiff_t)n > end - p)
Dan Gohman970d02c2017-03-30 23:58:19 +00001012 report_fatal_error("global initial value must be valid SLEB128");
1013 p += n;
1014 }
Dan Gohman82607f52017-02-24 23:46:05 +00001015 Globals.push_back(G);
1016 }
1017 }
1018
Dan Gohman970d02c2017-03-30 23:58:19 +00001019 // In the special .stack_pointer section, we've encoded the stack pointer
1020 // index.
1021 MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0);
1022 if (!StackPtr->getFragmentList().empty()) {
1023 if (StackPtr->getFragmentList().size() != 1)
1024 report_fatal_error("only one .stack_pointer fragment supported");
1025 const MCFragment &Frag = *StackPtr->begin();
1026 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1027 report_fatal_error("only data supported in .stack_pointer");
1028 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1029 if (!DataFrag.getFixups().empty())
1030 report_fatal_error("fixups not supported in .stack_pointer");
1031 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1032 if (Contents.size() != 4)
1033 report_fatal_error("only one entry supported in .stack_pointer");
1034 HasStackPointer = true;
1035 StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data();
1036 }
1037
Dan Gohmand934cb82017-02-24 23:18:00 +00001038 // Handle defined symbols.
1039 for (const MCSymbol &S : Asm.symbols()) {
1040 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1041 // or used in relocations.
1042 if (S.isTemporary() && S.getName().empty())
1043 continue;
1044 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1045 unsigned Index;
1046 if (WS.isFunction()) {
1047 // Prepare the function's type, if we haven't seen it yet.
1048 WasmFunctionType F;
1049 F.Returns = WS.getReturns();
1050 F.Params = WS.getParams();
1051 auto Pair =
1052 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
1053 if (Pair.second)
1054 FunctionTypes.push_back(F);
1055
Derek Schuffb8795392017-03-16 20:49:48 +00001056 int32_t Type = Pair.first->second;
Dan Gohmand934cb82017-02-24 23:18:00 +00001057
1058 if (WS.isDefined(/*SetUsed=*/false)) {
1059 // A definition. Take the next available index.
1060 Index = NumFuncImports + Functions.size();
1061
1062 // Prepare the function.
1063 WasmFunction Func;
1064 Func.Type = Type;
1065 Func.Sym = &WS;
1066 SymbolIndices[&WS] = Index;
1067 Functions.push_back(Func);
1068 } else {
1069 // An import; the index was assigned above.
1070 Index = SymbolIndices.find(&WS)->second;
1071 }
1072
1073 // If needed, prepare the function to be called indirectly.
1074 if (IsAddressTaken.count(&WS))
1075 TableElems.push_back(Index);
1076 } else {
Sam Cleggc38e9472017-06-02 01:05:24 +00001077 if (WS.isTemporary() && !WS.getSize())
1078 continue;
Dan Gohmand934cb82017-02-24 23:18:00 +00001079
1080 if (WS.isDefined(false)) {
Sam Cleggc38e9472017-06-02 01:05:24 +00001081 if (WS.getOffset() != 0)
1082 report_fatal_error("data sections must contain one variable each: " +
1083 WS.getName());
1084 if (!WS.getSize())
1085 report_fatal_error("data symbols must have a size set with .size: " +
1086 WS.getName());
1087
1088 int64_t Size = 0;
1089 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
1090 report_fatal_error(".size expression must be evaluatable");
1091
Dan Gohmand934cb82017-02-24 23:18:00 +00001092 MCSectionWasm &DataSection =
1093 static_cast<MCSectionWasm &>(WS.getSection());
1094
1095 if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection))
1096 report_fatal_error("data sections must contain at most one variable");
1097
1098 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
1099
1100 DataSection.setSectionOffset(DataBytes.size());
1101
1102 for (MCSection::iterator I = DataSection.begin(), E = DataSection.end();
1103 I != E; ++I) {
1104 const MCFragment &Frag = *I;
1105 if (Frag.hasInstructions())
1106 report_fatal_error("only data supported in data sections");
1107
1108 if (const MCAlignFragment *Align = dyn_cast<MCAlignFragment>(&Frag)) {
1109 if (Align->getValueSize() != 1)
1110 report_fatal_error("only byte values supported for alignment");
1111 // If nops are requested, use zeros, as this is the data section.
1112 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
1113 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
1114 Align->getAlignment()),
1115 DataBytes.size() +
1116 Align->getMaxBytesToEmit());
1117 DataBytes.resize(Size, Value);
1118 } else if (const MCFillFragment *Fill =
1119 dyn_cast<MCFillFragment>(&Frag)) {
1120 DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
1121 } else {
1122 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1123 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1124
1125 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
1126 }
1127 }
1128
Sam Clegg1c154a62017-05-25 21:08:07 +00001129 // For each global, prepare a corresponding wasm global holding its
1130 // address. For externals these will also be named exports.
1131 Index = NumGlobalImports + Globals.size();
Dan Gohmand934cb82017-02-24 23:18:00 +00001132
Sam Clegg1c154a62017-05-25 21:08:07 +00001133 WasmGlobal Global;
1134 Global.Type = PtrType;
1135 Global.IsMutable = false;
1136 Global.HasImport = false;
1137 Global.InitialValue = DataSection.getSectionOffset();
1138 Global.ImportIndex = 0;
1139 SymbolIndices[&WS] = Index;
1140 Globals.push_back(Global);
Dan Gohmand934cb82017-02-24 23:18:00 +00001141 }
1142 }
1143
1144 // If the symbol is visible outside this translation unit, export it.
1145 if (WS.isExternal()) {
1146 assert(WS.isDefined(false));
1147 WasmExport Export;
1148 Export.FieldName = WS.getName();
1149 Export.Index = Index;
1150
1151 if (WS.isFunction())
1152 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1153 else
1154 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1155
1156 Exports.push_back(Export);
1157 }
1158 }
1159
1160 // Add types for indirect function calls.
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001161 for (const WasmRelocationEntry &Fixup : CodeRelocations) {
1162 if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
1163 continue;
Dan Gohman970d02c2017-03-30 23:58:19 +00001164
Dan Gohmand934cb82017-02-24 23:18:00 +00001165 WasmFunctionType F;
1166 F.Returns = Fixup.Symbol->getReturns();
1167 F.Params = Fixup.Symbol->getParams();
1168 auto Pair =
1169 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
1170 if (Pair.second)
1171 FunctionTypes.push_back(F);
1172
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001173 TypeIndices[Fixup.Symbol] = Pair.first->second;
Dan Gohmand934cb82017-02-24 23:18:00 +00001174 }
1175
Dan Gohman18eafb62017-02-22 01:23:18 +00001176 // Write out the Wasm header.
1177 writeHeader(Asm);
1178
Sam Clegg9e15f352017-06-03 02:01:24 +00001179 writeTypeSection(FunctionTypes);
1180 writeImportSection(Imports);
1181 writeFunctionSection(Functions);
1182 writeTableSection(TableElems);
1183 writeMemorySection(DataBytes);
1184 writeGlobalSection(Globals);
1185 writeExportSection(Exports);
1186 // TODO: Start Section
1187 writeElemSection(TableElems);
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001188 writeCodeSection(Asm, Layout, Functions);
1189 uint64_t DataSectionHeaderSize = writeDataSection(DataBytes);
Sam Clegg9e15f352017-06-03 02:01:24 +00001190 writeNameSection(Functions, Imports, NumFuncImports);
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001191 writeCodeRelocSection();
1192 writeDataRelocSection(DataSectionHeaderSize);
Sam Clegg9e15f352017-06-03 02:01:24 +00001193 writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal);
Dan Gohman970d02c2017-03-30 23:58:19 +00001194
Dan Gohmand934cb82017-02-24 23:18:00 +00001195 // TODO: Translate the .comment section to the output.
Dan Gohmand934cb82017-02-24 23:18:00 +00001196 // TODO: Translate debug sections to the output.
Dan Gohman18eafb62017-02-22 01:23:18 +00001197}
1198
1199MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW,
1200 raw_pwrite_stream &OS) {
1201 return new WasmObjectWriter(MOTW, OS);
1202}