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