blob: 9b2031f05043bb677ba2602acb23de37cebbd2cc [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 {
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
Dan Gohman18eafb62017-02-22 01:23:18 +0000130class WasmObjectWriter : public MCObjectWriter {
131 /// Helper struct for containing some precomputed information on symbols.
132 struct WasmSymbolData {
133 const MCSymbolWasm *Symbol;
134 StringRef Name;
135
136 // Support lexicographic sorting.
137 bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; }
138 };
139
140 /// The target specific Wasm writer instance.
141 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
142
Dan Gohmand934cb82017-02-24 23:18:00 +0000143 // Relocations for fixing up references in the code section.
144 std::vector<WasmRelocationEntry> CodeRelocations;
145
146 // Relocations for fixing up references in the data section.
147 std::vector<WasmRelocationEntry> DataRelocations;
148
149 // Fixups for call_indirect type indices.
Dan Gohman970d02c2017-03-30 23:58:19 +0000150 std::vector<WasmRelocationEntry> TypeIndexFixups;
Dan Gohmand934cb82017-02-24 23:18:00 +0000151
152 // Index values to use for fixing up call_indirect type indices.
153 std::vector<uint32_t> TypeIndexFixupTypes;
154
Dan Gohman18eafb62017-02-22 01:23:18 +0000155 // TargetObjectWriter wrappers.
156 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
157 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
158 const MCFixup &Fixup, bool IsPCRel) const {
159 return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
160 }
161
Dan Gohmand934cb82017-02-24 23:18:00 +0000162 void startSection(SectionBookkeeping &Section, unsigned SectionId,
163 const char *Name = nullptr);
164 void endSection(SectionBookkeeping &Section);
165
Dan Gohman18eafb62017-02-22 01:23:18 +0000166public:
167 WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS)
168 : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {}
169
Dan Gohmand934cb82017-02-24 23:18:00 +0000170private:
Dan Gohman18eafb62017-02-22 01:23:18 +0000171 ~WasmObjectWriter() override;
172
173 void writeHeader(const MCAssembler &Asm);
174
175 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
176 const MCFragment *Fragment, const MCFixup &Fixup,
177 MCValue Target, bool &IsPCRel,
178 uint64_t &FixedValue) override;
179
180 void executePostLayoutBinding(MCAssembler &Asm,
181 const MCAsmLayout &Layout) override;
182
183 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
Sam Clegg9e15f352017-06-03 02:01:24 +0000184
185 void writeValueType(wasm::ValType Ty) {
186 encodeSLEB128(int32_t(Ty), getStream());
187 }
188
189 void writeTypeSection(const SmallVector<WasmFunctionType, 4> &FunctionTypes);
190 void writeImportSection(const SmallVector<WasmImport, 4> &Imports);
191 void writeFunctionSection(const SmallVector<WasmFunction, 4> &Functions);
192 void writeTableSection(const SmallVector<uint32_t, 4> &TableElems);
193 void writeMemorySection(const SmallVector<char, 0> &DataBytes);
194 void writeGlobalSection(const SmallVector<WasmGlobal, 4> &Globals);
195 void writeExportSection(const SmallVector<WasmExport, 4> &Exports);
196 void writeElemSection(const SmallVector<uint32_t, 4> &TableElems);
197 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
198 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
199 const SmallVector<WasmFunction, 4> &Functions);
200 uint64_t
201 writeDataSection(const SmallVector<char, 0> &DataBytes,
202 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices);
203 void writeNameSection(const SmallVector<WasmFunction, 4> &Functions,
204 const SmallVector<WasmImport, 4> &Imports,
205 uint32_t NumFuncImports);
206 void writeCodeRelocSection(
207 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices);
208 void writeDataRelocSection(
209 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
210 uint64_t DataSectionHeaderSize);
211 void writeLinkingMetaDataSection(bool HasStackPointer,
212 uint32_t StackPointerGlobal);
Dan Gohman18eafb62017-02-22 01:23:18 +0000213};
Sam Clegg9e15f352017-06-03 02:01:24 +0000214
Dan Gohman18eafb62017-02-22 01:23:18 +0000215} // end anonymous namespace
216
217WasmObjectWriter::~WasmObjectWriter() {}
218
Dan Gohmand934cb82017-02-24 23:18:00 +0000219// Return the padding size to write a 32-bit value into a 5-byte ULEB128.
220static unsigned PaddingFor5ByteULEB128(uint32_t X) {
221 return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u);
222}
223
224// Return the padding size to write a 32-bit value into a 5-byte SLEB128.
225static unsigned PaddingFor5ByteSLEB128(int32_t X) {
226 return 5 - getSLEB128Size(X);
227}
228
229// Write out a section header and a patchable section size field.
230void WasmObjectWriter::startSection(SectionBookkeeping &Section,
231 unsigned SectionId,
232 const char *Name) {
233 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) &&
234 "Only custom sections can have names");
235
Derek Schuffe2688c42017-03-14 20:23:22 +0000236 encodeULEB128(SectionId, getStream());
Dan Gohmand934cb82017-02-24 23:18:00 +0000237
238 Section.SizeOffset = getStream().tell();
239
240 // The section size. We don't know the size yet, so reserve enough space
241 // for any 32-bit value; we'll patch it later.
242 encodeULEB128(UINT32_MAX, getStream());
243
244 // The position where the section starts, for measuring its size.
245 Section.ContentsOffset = getStream().tell();
246
247 // Custom sections in wasm also have a string identifier.
248 if (SectionId == wasm::WASM_SEC_CUSTOM) {
249 encodeULEB128(strlen(Name), getStream());
250 writeBytes(Name);
251 }
252}
253
254// Now that the section is complete and we know how big it is, patch up the
255// section size field at the start of the section.
256void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
257 uint64_t Size = getStream().tell() - Section.ContentsOffset;
258 if (uint32_t(Size) != Size)
259 report_fatal_error("section size does not fit in a uint32_t");
260
261 unsigned Padding = PaddingFor5ByteULEB128(Size);
262
263 // Write the final section size to the payload_len field, which follows
264 // the section id byte.
265 uint8_t Buffer[16];
266 unsigned SizeLen = encodeULEB128(Size, Buffer, Padding);
267 assert(SizeLen == 5);
268 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
269}
270
Dan Gohman18eafb62017-02-22 01:23:18 +0000271// Emit the Wasm header.
272void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
Dan Gohman7ea5adf2017-02-22 18:50:20 +0000273 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic)));
274 writeLE32(wasm::WasmVersion);
Dan Gohman18eafb62017-02-22 01:23:18 +0000275}
276
277void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
278 const MCAsmLayout &Layout) {
279}
280
281void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
282 const MCAsmLayout &Layout,
283 const MCFragment *Fragment,
284 const MCFixup &Fixup, MCValue Target,
285 bool &IsPCRel, uint64_t &FixedValue) {
Dan Gohmand934cb82017-02-24 23:18:00 +0000286 MCSectionWasm &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
287 uint64_t C = Target.getConstant();
288 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
289 MCContext &Ctx = Asm.getContext();
290
291 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
292 assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
293 "Should not have constructed this");
294
295 // Let A, B and C being the components of Target and R be the location of
296 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
297 // If it is pcrel, we want to compute (A - B + C - R).
298
299 // In general, Wasm has no relocations for -B. It can only represent (A + C)
300 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
301 // replace B to implement it: (A - R - K + C)
302 if (IsPCRel) {
303 Ctx.reportError(
304 Fixup.getLoc(),
305 "No relocation available to represent this relative expression");
306 return;
307 }
308
309 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
310
311 if (SymB.isUndefined()) {
312 Ctx.reportError(Fixup.getLoc(),
313 Twine("symbol '") + SymB.getName() +
314 "' can not be undefined in a subtraction expression");
315 return;
316 }
317
318 assert(!SymB.isAbsolute() && "Should have been folded");
319 const MCSection &SecB = SymB.getSection();
320 if (&SecB != &FixupSection) {
321 Ctx.reportError(Fixup.getLoc(),
322 "Cannot represent a difference across sections");
323 return;
324 }
325
326 uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
327 uint64_t K = SymBOffset - FixupOffset;
328 IsPCRel = true;
329 C -= K;
330 }
331
332 // We either rejected the fixup or folded B into C at this point.
333 const MCSymbolRefExpr *RefA = Target.getSymA();
334 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
335
336 bool ViaWeakRef = false;
337 if (SymA && SymA->isVariable()) {
338 const MCExpr *Expr = SymA->getVariableValue();
339 if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
340 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
341 SymA = cast<MCSymbolWasm>(&Inner->getSymbol());
342 ViaWeakRef = true;
343 }
344 }
345 }
346
347 // Put any constant offset in an addend. Offsets can be negative, and
348 // LLVM expects wrapping, in contrast to wasm's immediates which can't
349 // be negative and don't wrap.
350 FixedValue = 0;
351
352 if (SymA) {
353 if (ViaWeakRef)
354 llvm_unreachable("weakref used in reloc not yet implemented");
355 else
356 SymA->setUsedInReloc();
357 }
358
359 if (RefA) {
360 if (RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX) {
Dan Gohman970d02c2017-03-30 23:58:19 +0000361 assert(C == 0);
362 WasmRelocationEntry Rec(FixupOffset, SymA, C,
363 wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB,
364 &FixupSection);
365 TypeIndexFixups.push_back(Rec);
Dan Gohmand934cb82017-02-24 23:18:00 +0000366 return;
367 }
368 }
369
370 unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel);
371
372 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
373
374 if (FixupSection.hasInstructions())
375 CodeRelocations.push_back(Rec);
376 else
377 DataRelocations.push_back(Rec);
378}
379
Dan Gohmand934cb82017-02-24 23:18:00 +0000380// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
381// to allow patching.
382static void
383WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
384 uint8_t Buffer[5];
385 unsigned Padding = PaddingFor5ByteULEB128(X);
386 unsigned SizeLen = encodeULEB128(X, Buffer, Padding);
387 assert(SizeLen == 5);
388 Stream.pwrite((char *)Buffer, SizeLen, Offset);
389}
390
391// Write X as an signed LEB value at offset Offset in Stream, padded
392// to allow patching.
393static void
394WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
395 uint8_t Buffer[5];
396 unsigned Padding = PaddingFor5ByteSLEB128(X);
397 unsigned SizeLen = encodeSLEB128(X, Buffer, Padding);
398 assert(SizeLen == 5);
399 Stream.pwrite((char *)Buffer, SizeLen, Offset);
400}
401
402// Write X as a plain integer value at offset Offset in Stream.
403static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
404 uint8_t Buffer[4];
405 support::endian::write32le(Buffer, X);
406 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
407}
408
409// Compute a value to write into the code at the location covered
410// by RelEntry. This value isn't used by the static linker, since
411// we have addends; it just serves to make the code more readable
412// and to make standalone wasm modules directly usable.
413static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) {
414 const MCSymbolWasm *Sym = RelEntry.Symbol;
415
416 // For undefined symbols, use a hopefully invalid value.
417 if (!Sym->isDefined(false))
418 return UINT32_MAX;
419
420 MCSectionWasm &Section =
421 cast<MCSectionWasm>(RelEntry.Symbol->getSection(false));
422 uint64_t Address = Section.getSectionOffset() + RelEntry.Addend;
423
424 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
425 uint32_t Value = Address;
426
427 return Value;
428}
429
430// Apply the portions of the relocation records that we can handle ourselves
431// directly.
432static void ApplyRelocations(
433 ArrayRef<WasmRelocationEntry> Relocations,
434 raw_pwrite_stream &Stream,
435 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
436 uint64_t ContentsOffset)
437{
438 for (const WasmRelocationEntry &RelEntry : Relocations) {
439 uint64_t Offset = ContentsOffset +
440 RelEntry.FixupSection->getSectionOffset() +
441 RelEntry.Offset;
442 switch (RelEntry.Type) {
443 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: {
Sam Clegg1c154a62017-05-25 21:08:07 +0000444 assert(SymbolIndices.count(RelEntry.Symbol));
Dan Gohmand934cb82017-02-24 23:18:00 +0000445 uint32_t Index = SymbolIndices[RelEntry.Symbol];
446 assert(RelEntry.Addend == 0);
447
448 WritePatchableLEB(Stream, Index, Offset);
449 break;
450 }
451 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: {
Sam Clegg1c154a62017-05-25 21:08:07 +0000452 assert(SymbolIndices.count(RelEntry.Symbol));
Dan Gohmand934cb82017-02-24 23:18:00 +0000453 uint32_t Index = SymbolIndices[RelEntry.Symbol];
454 assert(RelEntry.Addend == 0);
455
456 WritePatchableSLEB(Stream, Index, Offset);
457 break;
458 }
459 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: {
460 uint32_t Value = ProvisionalValue(RelEntry);
461
462 WritePatchableSLEB(Stream, Value, Offset);
463 break;
464 }
465 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: {
466 uint32_t Value = ProvisionalValue(RelEntry);
467
468 WritePatchableLEB(Stream, Value, Offset);
469 break;
470 }
471 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
Sam Clegg1c154a62017-05-25 21:08:07 +0000472 assert(SymbolIndices.count(RelEntry.Symbol));
Dan Gohmand934cb82017-02-24 23:18:00 +0000473 uint32_t Index = SymbolIndices[RelEntry.Symbol];
474 assert(RelEntry.Addend == 0);
475
476 WriteI32(Stream, Index, Offset);
477 break;
478 }
479 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: {
480 uint32_t Value = ProvisionalValue(RelEntry);
481
482 WriteI32(Stream, Value, Offset);
483 break;
484 }
485 default:
486 break;
487 }
488 }
489}
490
491// Write out the portions of the relocation records that the linker will
492// need to handle.
Sam Clegga06de022017-04-28 21:22:38 +0000493static void
494WriteRelocations(ArrayRef<WasmRelocationEntry> Relocations,
495 raw_pwrite_stream &Stream,
496 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
497 uint64_t HeaderSize) {
Dan Gohmand934cb82017-02-24 23:18:00 +0000498 for (const WasmRelocationEntry RelEntry : Relocations) {
499 encodeULEB128(RelEntry.Type, Stream);
500
501 uint64_t Offset = RelEntry.Offset +
Sam Clegga06de022017-04-28 21:22:38 +0000502 RelEntry.FixupSection->getSectionOffset() + HeaderSize;
Sam Clegg1c154a62017-05-25 21:08:07 +0000503 assert(SymbolIndices.count(RelEntry.Symbol));
Dan Gohmand934cb82017-02-24 23:18:00 +0000504 uint32_t Index = SymbolIndices[RelEntry.Symbol];
505 int64_t Addend = RelEntry.Addend;
506
507 switch (RelEntry.Type) {
508 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
509 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
510 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
511 encodeULEB128(Offset, Stream);
512 encodeULEB128(Index, Stream);
513 assert(Addend == 0 && "addends not supported for functions");
514 break;
515 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
516 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
517 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
518 encodeULEB128(Offset, Stream);
519 encodeULEB128(Index, Stream);
520 encodeSLEB128(Addend, Stream);
521 break;
522 default:
523 llvm_unreachable("unsupported relocation type");
524 }
525 }
Dan Gohman18eafb62017-02-22 01:23:18 +0000526}
527
Dan Gohman970d02c2017-03-30 23:58:19 +0000528// Write out the the type relocation records that the linker will
529// need to handle.
530static void WriteTypeRelocations(
531 ArrayRef<WasmRelocationEntry> TypeIndexFixups,
532 ArrayRef<uint32_t> TypeIndexFixupTypes,
533 raw_pwrite_stream &Stream)
534{
535 for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) {
536 const WasmRelocationEntry &Fixup = TypeIndexFixups[i];
537 uint32_t Type = TypeIndexFixupTypes[i];
538
539 assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB);
540 assert(Fixup.Addend == 0);
541
542 uint64_t Offset = Fixup.Offset +
543 Fixup.FixupSection->getSectionOffset();
544
545 encodeULEB128(Fixup.Type, Stream);
546 encodeULEB128(Offset, Stream);
547 encodeULEB128(Type, Stream);
548 }
549}
550
Sam Clegg9e15f352017-06-03 02:01:24 +0000551void WasmObjectWriter::writeTypeSection(
552 const SmallVector<WasmFunctionType, 4> &FunctionTypes) {
553 if (FunctionTypes.empty())
554 return;
555
556 SectionBookkeeping Section;
557 startSection(Section, wasm::WASM_SEC_TYPE);
558
559 encodeULEB128(FunctionTypes.size(), getStream());
560
561 for (const WasmFunctionType &FuncTy : FunctionTypes) {
562 encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream());
563 encodeULEB128(FuncTy.Params.size(), getStream());
564 for (wasm::ValType Ty : FuncTy.Params)
565 writeValueType(Ty);
566 encodeULEB128(FuncTy.Returns.size(), getStream());
567 for (wasm::ValType Ty : FuncTy.Returns)
568 writeValueType(Ty);
569 }
570
571 endSection(Section);
572}
573
574void WasmObjectWriter::writeImportSection(
575 const SmallVector<WasmImport, 4> &Imports) {
576 if (Imports.empty())
577 return;
578
579 SectionBookkeeping Section;
580 startSection(Section, wasm::WASM_SEC_IMPORT);
581
582 encodeULEB128(Imports.size(), getStream());
583 for (const WasmImport &Import : Imports) {
584 StringRef ModuleName = Import.ModuleName;
585 encodeULEB128(ModuleName.size(), getStream());
586 writeBytes(ModuleName);
587
588 StringRef FieldName = Import.FieldName;
589 encodeULEB128(FieldName.size(), getStream());
590 writeBytes(FieldName);
591
592 encodeULEB128(Import.Kind, getStream());
593
594 switch (Import.Kind) {
595 case wasm::WASM_EXTERNAL_FUNCTION:
596 encodeULEB128(Import.Type, getStream());
597 break;
598 case wasm::WASM_EXTERNAL_GLOBAL:
599 encodeSLEB128(int32_t(Import.Type), getStream());
600 encodeULEB128(0, getStream()); // mutability
601 break;
602 default:
603 llvm_unreachable("unsupported import kind");
604 }
605 }
606
607 endSection(Section);
608}
609
610void WasmObjectWriter::writeFunctionSection(
611 const SmallVector<WasmFunction, 4> &Functions) {
612 if (Functions.empty())
613 return;
614
615 SectionBookkeeping Section;
616 startSection(Section, wasm::WASM_SEC_FUNCTION);
617
618 encodeULEB128(Functions.size(), getStream());
619 for (const WasmFunction &Func : Functions)
620 encodeULEB128(Func.Type, getStream());
621
622 endSection(Section);
623}
624
625void WasmObjectWriter::writeTableSection(
626 const SmallVector<uint32_t, 4> &TableElems) {
627 // 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.
630 SectionBookkeeping Section;
631 startSection(Section, wasm::WASM_SEC_TABLE);
632
633 // The number of tables, fixed to 1 for now.
634 encodeULEB128(1, getStream());
635
636 encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream());
637
638 encodeULEB128(0, getStream()); // flags
639 encodeULEB128(TableElems.size(), getStream()); // initial
640
641 endSection(Section);
642}
643
644void WasmObjectWriter::writeMemorySection(
645 const SmallVector<char, 0> &DataBytes) {
646 // For now, always emit the memory section, since loads and stores are not
647 // valid without it. In the future, we could perhaps be more clever and omit
648 // it if there are no loads or stores.
649 SectionBookkeeping Section;
650 uint32_t NumPages =
651 (DataBytes.size() + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
652
653 startSection(Section, wasm::WASM_SEC_MEMORY);
654 encodeULEB128(1, getStream()); // number of memory spaces
655
656 encodeULEB128(0, getStream()); // flags
657 encodeULEB128(NumPages, getStream()); // initial
658
659 endSection(Section);
660}
661
662void WasmObjectWriter::writeGlobalSection(
663 const SmallVector<WasmGlobal, 4> &Globals) {
664 if (Globals.empty())
665 return;
666
667 SectionBookkeeping Section;
668 startSection(Section, wasm::WASM_SEC_GLOBAL);
669
670 encodeULEB128(Globals.size(), getStream());
671 for (const WasmGlobal &Global : Globals) {
672 writeValueType(Global.Type);
673 write8(Global.IsMutable);
674
675 if (Global.HasImport) {
676 assert(Global.InitialValue == 0);
677 write8(wasm::WASM_OPCODE_GET_GLOBAL);
678 encodeULEB128(Global.ImportIndex, getStream());
679 } else {
680 assert(Global.ImportIndex == 0);
681 write8(wasm::WASM_OPCODE_I32_CONST);
682 encodeSLEB128(Global.InitialValue, getStream()); // offset
683 }
684 write8(wasm::WASM_OPCODE_END);
685 }
686
687 endSection(Section);
688}
689
690void WasmObjectWriter::writeExportSection(
691 const SmallVector<WasmExport, 4> &Exports) {
692 if (Exports.empty())
693 return;
694
695 SectionBookkeeping Section;
696 startSection(Section, wasm::WASM_SEC_EXPORT);
697
698 encodeULEB128(Exports.size(), getStream());
699 for (const WasmExport &Export : Exports) {
700 encodeULEB128(Export.FieldName.size(), getStream());
701 writeBytes(Export.FieldName);
702
703 encodeSLEB128(Export.Kind, getStream());
704
705 encodeULEB128(Export.Index, getStream());
706 }
707
708 endSection(Section);
709}
710
711void WasmObjectWriter::writeElemSection(
712 const SmallVector<uint32_t, 4> &TableElems) {
713 if (TableElems.empty())
714 return;
715
716 SectionBookkeeping Section;
717 startSection(Section, wasm::WASM_SEC_ELEM);
718
719 encodeULEB128(1, getStream()); // number of "segments"
720 encodeULEB128(0, getStream()); // the table index
721
722 // init expr for starting offset
723 write8(wasm::WASM_OPCODE_I32_CONST);
724 encodeSLEB128(0, getStream());
725 write8(wasm::WASM_OPCODE_END);
726
727 encodeULEB128(TableElems.size(), getStream());
728 for (uint32_t Elem : TableElems)
729 encodeULEB128(Elem, getStream());
730
731 endSection(Section);
732}
733
734void WasmObjectWriter::writeCodeSection(
735 const MCAssembler &Asm, const MCAsmLayout &Layout,
736 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
737 const SmallVector<WasmFunction, 4> &Functions) {
738 if (Functions.empty())
739 return;
740
741 SectionBookkeeping Section;
742 startSection(Section, wasm::WASM_SEC_CODE);
743
744 encodeULEB128(Functions.size(), getStream());
745
746 for (const WasmFunction &Func : Functions) {
747 MCSectionWasm &FuncSection =
748 static_cast<MCSectionWasm &>(Func.Sym->getSection());
749
750 if (Func.Sym->isVariable())
751 report_fatal_error("weak symbols not supported yet");
752
753 if (Func.Sym->getOffset() != 0)
754 report_fatal_error("function sections must contain one function each");
755
756 if (!Func.Sym->getSize())
757 report_fatal_error("function symbols must have a size set with .size");
758
759 int64_t Size = 0;
760 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
761 report_fatal_error(".size expression must be evaluatable");
762
763 encodeULEB128(Size, getStream());
764
765 FuncSection.setSectionOffset(getStream().tell() -
766 Section.ContentsOffset);
767
768 Asm.writeSectionData(&FuncSection, Layout);
769 }
770
771 // Apply the type index fixups for call_indirect etc. instructions.
772 for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) {
773 uint32_t Type = TypeIndexFixupTypes[i];
774 unsigned Padding = PaddingFor5ByteULEB128(Type);
775
776 const WasmRelocationEntry &Fixup = TypeIndexFixups[i];
777 assert(Fixup.Addend == 0);
778 assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB);
779 uint64_t Offset = Fixup.Offset +
780 Fixup.FixupSection->getSectionOffset();
781
782 uint8_t Buffer[16];
783 unsigned SizeLen = encodeULEB128(Type, Buffer, Padding);
784 assert(SizeLen == 5);
785 getStream().pwrite((char *)Buffer, SizeLen,
786 Section.ContentsOffset + Offset);
787 }
788
789 // Apply fixups.
790 ApplyRelocations(CodeRelocations, getStream(), SymbolIndices,
791 Section.ContentsOffset);
792
793 endSection(Section);
794}
795
796uint64_t WasmObjectWriter::writeDataSection(
797 const SmallVector<char, 0> &DataBytes,
798 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) {
799 if (DataBytes.empty())
800 return 0;
801
802 SectionBookkeeping Section;
803 startSection(Section, wasm::WASM_SEC_DATA);
804
805 encodeULEB128(1, getStream()); // count
806 encodeULEB128(0, getStream()); // memory index
807 write8(wasm::WASM_OPCODE_I32_CONST);
808 encodeSLEB128(0, getStream()); // offset
809 write8(wasm::WASM_OPCODE_END);
810 encodeULEB128(DataBytes.size(), getStream()); // size
811 uint32_t HeaderSize = getStream().tell() - Section.ContentsOffset;
812 writeBytes(DataBytes); // data
813
814 // Apply fixups.
815 ApplyRelocations(DataRelocations, getStream(), SymbolIndices,
816 Section.ContentsOffset + HeaderSize);
817
818 endSection(Section);
819 return HeaderSize;
820}
821
822void WasmObjectWriter::writeNameSection(
823 const SmallVector<WasmFunction, 4> &Functions,
824 const SmallVector<WasmImport, 4> &Imports,
825 unsigned NumFuncImports) {
826 uint32_t TotalFunctions = NumFuncImports + Functions.size();
827 if (TotalFunctions == 0)
828 return;
829
830 SectionBookkeeping Section;
831 startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
832 SectionBookkeeping SubSection;
833 startSection(SubSection, wasm::WASM_NAMES_FUNCTION);
834
835 encodeULEB128(TotalFunctions, getStream());
836 uint32_t Index = 0;
837 for (const WasmImport &Import : Imports) {
838 if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
839 encodeULEB128(Index, getStream());
840 encodeULEB128(Import.FieldName.size(), getStream());
841 writeBytes(Import.FieldName);
842 ++Index;
843 }
844 }
845 for (const WasmFunction &Func : Functions) {
846 encodeULEB128(Index, getStream());
847 encodeULEB128(Func.Sym->getName().size(), getStream());
848 writeBytes(Func.Sym->getName());
849 ++Index;
850 }
851
852 endSection(SubSection);
853 endSection(Section);
854}
855
856void WasmObjectWriter::writeCodeRelocSection(
857 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices) {
858 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
859 // for descriptions of the reloc sections.
860
861 if (CodeRelocations.empty())
862 return;
863
864 SectionBookkeeping Section;
865 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
866
867 encodeULEB128(wasm::WASM_SEC_CODE, getStream());
868 encodeULEB128(CodeRelocations.size() + TypeIndexFixups.size(), getStream());
869
870 WriteRelocations(CodeRelocations, getStream(), SymbolIndices, 0);
871 WriteTypeRelocations(TypeIndexFixups, TypeIndexFixupTypes, getStream());
872
873 endSection(Section);
874}
875
876void WasmObjectWriter::writeDataRelocSection(
877 DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
878 uint64_t DataSectionHeaderSize) {
879 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
880 // for descriptions of the reloc sections.
881
882 if (DataRelocations.empty())
883 return;
884
885 SectionBookkeeping Section;
886 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
887
888 encodeULEB128(wasm::WASM_SEC_DATA, getStream());
889 encodeULEB128(DataRelocations.size(), getStream());
890
891 WriteRelocations(DataRelocations, getStream(), SymbolIndices,
892 DataSectionHeaderSize);
893
894 endSection(Section);
895}
896
897void WasmObjectWriter::writeLinkingMetaDataSection(
898 bool HasStackPointer, uint32_t StackPointerGlobal) {
899 if (!HasStackPointer)
900 return;
901 SectionBookkeeping Section;
902 startSection(Section, wasm::WASM_SEC_CUSTOM, "linking");
903
904 encodeULEB128(1, getStream()); // count
905
906 encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type
907 encodeULEB128(StackPointerGlobal, getStream()); // id
908
909 endSection(Section);
910}
911
Dan Gohman18eafb62017-02-22 01:23:18 +0000912void WasmObjectWriter::writeObject(MCAssembler &Asm,
913 const MCAsmLayout &Layout) {
Dan Gohman82607f52017-02-24 23:46:05 +0000914 MCContext &Ctx = Asm.getContext();
Derek Schuffb8795392017-03-16 20:49:48 +0000915 wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32;
Dan Gohmand934cb82017-02-24 23:18:00 +0000916
917 // Collect information from the available symbols.
Derek Schuffb8795392017-03-16 20:49:48 +0000918 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo>
Dan Gohmand934cb82017-02-24 23:18:00 +0000919 FunctionTypeIndices;
920 SmallVector<WasmFunctionType, 4> FunctionTypes;
921 SmallVector<WasmFunction, 4> Functions;
922 SmallVector<uint32_t, 4> TableElems;
923 SmallVector<WasmGlobal, 4> Globals;
924 SmallVector<WasmImport, 4> Imports;
925 SmallVector<WasmExport, 4> Exports;
926 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices;
927 SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken;
928 unsigned NumFuncImports = 0;
929 unsigned NumGlobalImports = 0;
930 SmallVector<char, 0> DataBytes;
Dan Gohman970d02c2017-03-30 23:58:19 +0000931 uint32_t StackPointerGlobal = 0;
932 bool HasStackPointer = false;
Dan Gohmand934cb82017-02-24 23:18:00 +0000933
934 // Populate the IsAddressTaken set.
935 for (WasmRelocationEntry RelEntry : CodeRelocations) {
936 switch (RelEntry.Type) {
937 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
938 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
939 IsAddressTaken.insert(RelEntry.Symbol);
940 break;
941 default:
942 break;
943 }
944 }
945 for (WasmRelocationEntry RelEntry : DataRelocations) {
946 switch (RelEntry.Type) {
947 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
948 case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
949 IsAddressTaken.insert(RelEntry.Symbol);
950 break;
951 default:
952 break;
953 }
954 }
955
956 // Populate the Imports set.
957 for (const MCSymbol &S : Asm.symbols()) {
958 const auto &WS = static_cast<const MCSymbolWasm &>(S);
Derek Schuffb8795392017-03-16 20:49:48 +0000959 int32_t Type;
Dan Gohmand934cb82017-02-24 23:18:00 +0000960
961 if (WS.isFunction()) {
962 // Prepare the function's type, if we haven't seen it yet.
963 WasmFunctionType F;
964 F.Returns = WS.getReturns();
965 F.Params = WS.getParams();
966 auto Pair =
967 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
968 if (Pair.second)
969 FunctionTypes.push_back(F);
970
971 Type = Pair.first->second;
972 } else {
Derek Schuffb8795392017-03-16 20:49:48 +0000973 Type = int32_t(PtrType);
Dan Gohmand934cb82017-02-24 23:18:00 +0000974 }
975
976 // If the symbol is not defined in this translation unit, import it.
977 if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) {
978 WasmImport Import;
979 Import.ModuleName = WS.getModuleName();
980 Import.FieldName = WS.getName();
981
982 if (WS.isFunction()) {
983 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
984 Import.Type = Type;
985 SymbolIndices[&WS] = NumFuncImports;
986 ++NumFuncImports;
987 } else {
988 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
989 Import.Type = Type;
990 SymbolIndices[&WS] = NumGlobalImports;
991 ++NumGlobalImports;
992 }
993
994 Imports.push_back(Import);
995 }
996 }
997
Dan Gohman82607f52017-02-24 23:46:05 +0000998 // In the special .global_variables section, we've encoded global
999 // variables used by the function. Translate them into the Globals
1000 // list.
1001 MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0);
1002 if (!GlobalVars->getFragmentList().empty()) {
1003 if (GlobalVars->getFragmentList().size() != 1)
1004 report_fatal_error("only one .global_variables fragment supported");
1005 const MCFragment &Frag = *GlobalVars->begin();
1006 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1007 report_fatal_error("only data supported in .global_variables");
1008 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1009 if (!DataFrag.getFixups().empty())
1010 report_fatal_error("fixups not supported in .global_variables");
1011 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
Dan Gohman970d02c2017-03-30 23:58:19 +00001012 for (const uint8_t *p = (const uint8_t *)Contents.data(),
1013 *end = (const uint8_t *)Contents.data() + Contents.size();
1014 p != end; ) {
Dan Gohman82607f52017-02-24 23:46:05 +00001015 WasmGlobal G;
Dan Gohman970d02c2017-03-30 23:58:19 +00001016 if (end - p < 3)
1017 report_fatal_error("truncated global variable encoding");
1018 G.Type = wasm::ValType(int8_t(*p++));
1019 G.IsMutable = bool(*p++);
1020 G.HasImport = bool(*p++);
1021 if (G.HasImport) {
1022 G.InitialValue = 0;
1023
1024 WasmImport Import;
1025 Import.ModuleName = (const char *)p;
1026 const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p);
1027 if (!nul)
1028 report_fatal_error("global module name must be nul-terminated");
1029 p = nul + 1;
1030 nul = (const uint8_t *)memchr(p, '\0', end - p);
1031 if (!nul)
1032 report_fatal_error("global base name must be nul-terminated");
1033 Import.FieldName = (const char *)p;
1034 p = nul + 1;
1035
1036 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1037 Import.Type = int32_t(G.Type);
1038
1039 G.ImportIndex = NumGlobalImports;
1040 ++NumGlobalImports;
1041
1042 Imports.push_back(Import);
1043 } else {
1044 unsigned n;
1045 G.InitialValue = decodeSLEB128(p, &n);
1046 G.ImportIndex = 0;
Simon Pilgrimc8da0c02017-03-31 10:45:35 +00001047 if ((ptrdiff_t)n > end - p)
Dan Gohman970d02c2017-03-30 23:58:19 +00001048 report_fatal_error("global initial value must be valid SLEB128");
1049 p += n;
1050 }
Dan Gohman82607f52017-02-24 23:46:05 +00001051 Globals.push_back(G);
1052 }
1053 }
1054
Dan Gohman970d02c2017-03-30 23:58:19 +00001055 // In the special .stack_pointer section, we've encoded the stack pointer
1056 // index.
1057 MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0);
1058 if (!StackPtr->getFragmentList().empty()) {
1059 if (StackPtr->getFragmentList().size() != 1)
1060 report_fatal_error("only one .stack_pointer fragment supported");
1061 const MCFragment &Frag = *StackPtr->begin();
1062 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1063 report_fatal_error("only data supported in .stack_pointer");
1064 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1065 if (!DataFrag.getFixups().empty())
1066 report_fatal_error("fixups not supported in .stack_pointer");
1067 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1068 if (Contents.size() != 4)
1069 report_fatal_error("only one entry supported in .stack_pointer");
1070 HasStackPointer = true;
1071 StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data();
1072 }
1073
Dan Gohmand934cb82017-02-24 23:18:00 +00001074 // Handle defined symbols.
1075 for (const MCSymbol &S : Asm.symbols()) {
1076 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1077 // or used in relocations.
1078 if (S.isTemporary() && S.getName().empty())
1079 continue;
1080 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1081 unsigned Index;
1082 if (WS.isFunction()) {
1083 // Prepare the function's type, if we haven't seen it yet.
1084 WasmFunctionType F;
1085 F.Returns = WS.getReturns();
1086 F.Params = WS.getParams();
1087 auto Pair =
1088 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
1089 if (Pair.second)
1090 FunctionTypes.push_back(F);
1091
Derek Schuffb8795392017-03-16 20:49:48 +00001092 int32_t Type = Pair.first->second;
Dan Gohmand934cb82017-02-24 23:18:00 +00001093
1094 if (WS.isDefined(/*SetUsed=*/false)) {
1095 // A definition. Take the next available index.
1096 Index = NumFuncImports + Functions.size();
1097
1098 // Prepare the function.
1099 WasmFunction Func;
1100 Func.Type = Type;
1101 Func.Sym = &WS;
1102 SymbolIndices[&WS] = Index;
1103 Functions.push_back(Func);
1104 } else {
1105 // An import; the index was assigned above.
1106 Index = SymbolIndices.find(&WS)->second;
1107 }
1108
1109 // If needed, prepare the function to be called indirectly.
1110 if (IsAddressTaken.count(&WS))
1111 TableElems.push_back(Index);
1112 } else {
Sam Cleggc38e9472017-06-02 01:05:24 +00001113 if (WS.isTemporary() && !WS.getSize())
1114 continue;
Dan Gohmand934cb82017-02-24 23:18:00 +00001115
1116 if (WS.isDefined(false)) {
Sam Cleggc38e9472017-06-02 01:05:24 +00001117 if (WS.getOffset() != 0)
1118 report_fatal_error("data sections must contain one variable each: " +
1119 WS.getName());
1120 if (!WS.getSize())
1121 report_fatal_error("data symbols must have a size set with .size: " +
1122 WS.getName());
1123
1124 int64_t Size = 0;
1125 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
1126 report_fatal_error(".size expression must be evaluatable");
1127
Dan Gohmand934cb82017-02-24 23:18:00 +00001128 MCSectionWasm &DataSection =
1129 static_cast<MCSectionWasm &>(WS.getSection());
1130
1131 if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection))
1132 report_fatal_error("data sections must contain at most one variable");
1133
1134 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
1135
1136 DataSection.setSectionOffset(DataBytes.size());
1137
1138 for (MCSection::iterator I = DataSection.begin(), E = DataSection.end();
1139 I != E; ++I) {
1140 const MCFragment &Frag = *I;
1141 if (Frag.hasInstructions())
1142 report_fatal_error("only data supported in data sections");
1143
1144 if (const MCAlignFragment *Align = dyn_cast<MCAlignFragment>(&Frag)) {
1145 if (Align->getValueSize() != 1)
1146 report_fatal_error("only byte values supported for alignment");
1147 // If nops are requested, use zeros, as this is the data section.
1148 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
1149 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
1150 Align->getAlignment()),
1151 DataBytes.size() +
1152 Align->getMaxBytesToEmit());
1153 DataBytes.resize(Size, Value);
1154 } else if (const MCFillFragment *Fill =
1155 dyn_cast<MCFillFragment>(&Frag)) {
1156 DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
1157 } else {
1158 const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
1159 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1160
1161 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
1162 }
1163 }
1164
Sam Clegg1c154a62017-05-25 21:08:07 +00001165 // For each global, prepare a corresponding wasm global holding its
1166 // address. For externals these will also be named exports.
1167 Index = NumGlobalImports + Globals.size();
Dan Gohmand934cb82017-02-24 23:18:00 +00001168
Sam Clegg1c154a62017-05-25 21:08:07 +00001169 WasmGlobal Global;
1170 Global.Type = PtrType;
1171 Global.IsMutable = false;
1172 Global.HasImport = false;
1173 Global.InitialValue = DataSection.getSectionOffset();
1174 Global.ImportIndex = 0;
1175 SymbolIndices[&WS] = Index;
1176 Globals.push_back(Global);
Dan Gohmand934cb82017-02-24 23:18:00 +00001177 }
1178 }
1179
1180 // If the symbol is visible outside this translation unit, export it.
1181 if (WS.isExternal()) {
1182 assert(WS.isDefined(false));
1183 WasmExport Export;
1184 Export.FieldName = WS.getName();
1185 Export.Index = Index;
1186
1187 if (WS.isFunction())
1188 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1189 else
1190 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1191
1192 Exports.push_back(Export);
1193 }
1194 }
1195
1196 // Add types for indirect function calls.
Dan Gohman970d02c2017-03-30 23:58:19 +00001197 for (const WasmRelocationEntry &Fixup : TypeIndexFixups) {
1198 assert(Fixup.Addend == 0);
1199 assert(Fixup.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB);
1200
Dan Gohmand934cb82017-02-24 23:18:00 +00001201 WasmFunctionType F;
1202 F.Returns = Fixup.Symbol->getReturns();
1203 F.Params = Fixup.Symbol->getParams();
1204 auto Pair =
1205 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
1206 if (Pair.second)
1207 FunctionTypes.push_back(F);
1208
1209 TypeIndexFixupTypes.push_back(Pair.first->second);
1210 }
1211
Dan Gohman18eafb62017-02-22 01:23:18 +00001212 // Write out the Wasm header.
1213 writeHeader(Asm);
1214
Sam Clegg9e15f352017-06-03 02:01:24 +00001215 writeTypeSection(FunctionTypes);
1216 writeImportSection(Imports);
1217 writeFunctionSection(Functions);
1218 writeTableSection(TableElems);
1219 writeMemorySection(DataBytes);
1220 writeGlobalSection(Globals);
1221 writeExportSection(Exports);
1222 // TODO: Start Section
1223 writeElemSection(TableElems);
1224 writeCodeSection(Asm, Layout, SymbolIndices, Functions);
1225 uint64_t DataSectionHeaderSize = writeDataSection(DataBytes, SymbolIndices);
1226 writeNameSection(Functions, Imports, NumFuncImports);
1227 writeCodeRelocSection(SymbolIndices);
1228 writeDataRelocSection(SymbolIndices, DataSectionHeaderSize);
1229 writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal);
Dan Gohman970d02c2017-03-30 23:58:19 +00001230
Dan Gohmand934cb82017-02-24 23:18:00 +00001231 // TODO: Translate the .comment section to the output.
Dan Gohmand934cb82017-02-24 23:18:00 +00001232 // TODO: Translate debug sections to the output.
Dan Gohman18eafb62017-02-22 01:23:18 +00001233}
1234
1235MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW,
1236 raw_pwrite_stream &OS) {
1237 return new WasmObjectWriter(MOTW, OS);
1238}