blob: 0e1227085044e0adc89f3e8bcba6d5ba7239aeaf [file] [log] [blame]
Dan Gohman18eafb62017-02-22 01:23:18 +00001//===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements Wasm object file writer information.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/SmallPtrSet.h"
Zachary Turner264b5d92017-06-07 03:48:56 +000016#include "llvm/BinaryFormat/Wasm.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000017#include "llvm/MC/MCAsmBackend.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000018#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"
Dan Gohman18eafb62017-02-22 01:23:18 +000023#include "llvm/MC/MCObjectWriter.h"
24#include "llvm/MC/MCSectionWasm.h"
25#include "llvm/MC/MCSymbolWasm.h"
26#include "llvm/MC/MCValue.h"
27#include "llvm/MC/MCWasmObjectWriter.h"
Dan Gohmand934cb82017-02-24 23:18:00 +000028#include "llvm/Support/Casting.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000029#include "llvm/Support/Debug.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000030#include "llvm/Support/ErrorHandling.h"
Dan Gohmand934cb82017-02-24 23:18:00 +000031#include "llvm/Support/LEB128.h"
Dan Gohman18eafb62017-02-22 01:23:18 +000032#include "llvm/Support/StringSaver.h"
33#include <vector>
34
35using namespace llvm;
36
Sam Clegg5e3d33a2017-07-07 02:01:29 +000037#define DEBUG_TYPE "mc"
Dan Gohman18eafb62017-02-22 01:23:18 +000038
39namespace {
Sam Clegg9e15f352017-06-03 02:01:24 +000040
Sam Clegg30e1bbc2018-01-19 18:57:01 +000041// Went we ceate the indirect function table we start at 1, so that there is
42// and emtpy slot at 0 and therefore calling a null function pointer will trap.
43static const uint32_t kInitialTableOffset = 1;
44
Dan Gohmand934cb82017-02-24 23:18:00 +000045// For patching purposes, we need to remember where each section starts, both
46// for patching up the section size field, and for patching up references to
47// locations within the section.
48struct SectionBookkeeping {
49 // Where the size of the section is written.
50 uint64_t SizeOffset;
51 // Where the contents of the section starts (after the header).
52 uint64_t ContentsOffset;
Sam Clegg6f08c842018-04-24 18:11:36 +000053 uint32_t Index;
Dan Gohmand934cb82017-02-24 23:18:00 +000054};
55
Sam Clegg9e15f352017-06-03 02:01:24 +000056// The signature of a wasm function, in a struct capable of being used as a
57// DenseMap key.
58struct WasmFunctionType {
59 // Support empty and tombstone instances, needed by DenseMap.
60 enum { Plain, Empty, Tombstone } State;
61
62 // The return types of the function.
63 SmallVector<wasm::ValType, 1> Returns;
64
65 // The parameter types of the function.
66 SmallVector<wasm::ValType, 4> Params;
67
68 WasmFunctionType() : State(Plain) {}
69
70 bool operator==(const WasmFunctionType &Other) const {
71 return State == Other.State && Returns == Other.Returns &&
72 Params == Other.Params;
73 }
74};
75
76// Traits for using WasmFunctionType in a DenseMap.
77struct WasmFunctionTypeDenseMapInfo {
78 static WasmFunctionType getEmptyKey() {
79 WasmFunctionType FuncTy;
80 FuncTy.State = WasmFunctionType::Empty;
81 return FuncTy;
82 }
83 static WasmFunctionType getTombstoneKey() {
84 WasmFunctionType FuncTy;
85 FuncTy.State = WasmFunctionType::Tombstone;
86 return FuncTy;
87 }
88 static unsigned getHashValue(const WasmFunctionType &FuncTy) {
89 uintptr_t Value = FuncTy.State;
90 for (wasm::ValType Ret : FuncTy.Returns)
91 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret));
92 for (wasm::ValType Param : FuncTy.Params)
93 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param));
94 return Value;
95 }
96 static bool isEqual(const WasmFunctionType &LHS,
97 const WasmFunctionType &RHS) {
98 return LHS == RHS;
99 }
100};
101
Sam Clegg7c395942017-09-14 23:07:53 +0000102// A wasm data segment. A wasm binary contains only a single data section
103// but that can contain many segments, each with their own virtual location
104// in memory. Each MCSection data created by llvm is modeled as its own
105// wasm data segment.
106struct WasmDataSegment {
107 MCSectionWasm *Section;
Sam Cleggd95ed952017-09-20 19:03:35 +0000108 StringRef Name;
Sam Clegg7c395942017-09-14 23:07:53 +0000109 uint32_t Offset;
Sam Clegg63ebb812017-09-29 16:50:08 +0000110 uint32_t Alignment;
111 uint32_t Flags;
Sam Clegg7c395942017-09-14 23:07:53 +0000112 SmallVector<char, 4> Data;
113};
114
Sam Clegg9e15f352017-06-03 02:01:24 +0000115// A wasm function to be written into the function section.
116struct WasmFunction {
117 int32_t Type;
118 const MCSymbolWasm *Sym;
119};
120
Sam Clegg9e15f352017-06-03 02:01:24 +0000121// A wasm global to be written into the global section.
122struct WasmGlobal {
Sam Clegg6e7f1822018-01-31 19:50:14 +0000123 wasm::WasmGlobalType Type;
Sam Clegg9e15f352017-06-03 02:01:24 +0000124 uint64_t InitialValue;
Sam Clegg9e15f352017-06-03 02:01:24 +0000125};
126
Sam Cleggea7cace2018-01-09 23:43:14 +0000127// Information about a single item which is part of a COMDAT. For each data
128// segment or function which is in the COMDAT, there is a corresponding
129// WasmComdatEntry.
130struct WasmComdatEntry {
131 unsigned Kind;
132 uint32_t Index;
133};
134
Sam Clegg6dc65e92017-06-06 16:38:59 +0000135// Information about a single relocation.
136struct WasmRelocationEntry {
Sam Cleggfe6414b2017-06-21 23:46:41 +0000137 uint64_t Offset; // Where is the relocation.
138 const MCSymbolWasm *Symbol; // The symbol to relocate with.
139 int64_t Addend; // A value to add to the symbol.
140 unsigned Type; // The type of the relocation.
141 const MCSectionWasm *FixupSection;// The section the relocation is targeting.
Sam Clegg6dc65e92017-06-06 16:38:59 +0000142
143 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
144 int64_t Addend, unsigned Type,
Sam Cleggfe6414b2017-06-21 23:46:41 +0000145 const MCSectionWasm *FixupSection)
Sam Clegg6dc65e92017-06-06 16:38:59 +0000146 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
147 FixupSection(FixupSection) {}
148
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000149 bool hasAddend() const {
150 switch (Type) {
Sam Clegg13a2e892017-09-01 17:32:01 +0000151 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
152 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
153 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000154 return true;
155 default:
156 return false;
157 }
158 }
159
Sam Clegg6dc65e92017-06-06 16:38:59 +0000160 void print(raw_ostream &Out) const {
Sam Clegg9bf73c02017-07-05 20:25:08 +0000161 Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend
Sam Clegg759631c2017-09-15 20:54:59 +0000162 << ", Type=" << Type
163 << ", FixupSection=" << FixupSection->getSectionName();
Sam Clegg6dc65e92017-06-06 16:38:59 +0000164 }
Sam Cleggb7787fd2017-06-20 04:04:59 +0000165
Aaron Ballman615eb472017-10-15 14:32:27 +0000166#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
Sam Cleggb7787fd2017-06-20 04:04:59 +0000167 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
168#endif
Sam Clegg6dc65e92017-06-06 16:38:59 +0000169};
170
Sam Cleggcfd44a22018-04-05 17:01:39 +0000171struct WasmCustomSection {
172 StringRef Name;
173 const SmallVectorImpl<char> &Contents;
174
175 WasmCustomSection(StringRef Name, const SmallVectorImpl<char> &Contents)
176 : Name(Name), Contents(Contents) {}
177};
178
Sam Clegg1fb8daa2017-06-20 05:05:10 +0000179#if !defined(NDEBUG)
Sam Clegg7f055de2017-06-20 04:47:58 +0000180raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
Sam Cleggb7787fd2017-06-20 04:04:59 +0000181 Rel.print(OS);
182 return OS;
183}
Sam Clegg1fb8daa2017-06-20 05:05:10 +0000184#endif
Sam Cleggb7787fd2017-06-20 04:04:59 +0000185
Dan Gohman18eafb62017-02-22 01:23:18 +0000186class WasmObjectWriter : public MCObjectWriter {
Dan Gohman18eafb62017-02-22 01:23:18 +0000187 /// The target specific Wasm writer instance.
188 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
189
Dan Gohmand934cb82017-02-24 23:18:00 +0000190 // Relocations for fixing up references in the code section.
191 std::vector<WasmRelocationEntry> CodeRelocations;
Sam Clegg6f08c842018-04-24 18:11:36 +0000192 uint32_t CodeSectionIndex;
Dan Gohmand934cb82017-02-24 23:18:00 +0000193
194 // Relocations for fixing up references in the data section.
195 std::vector<WasmRelocationEntry> DataRelocations;
Sam Clegg6f08c842018-04-24 18:11:36 +0000196 uint32_t DataSectionIndex;
Dan Gohmand934cb82017-02-24 23:18:00 +0000197
Dan Gohmand934cb82017-02-24 23:18:00 +0000198 // Index values to use for fixing up call_indirect type indices.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000199 // Maps function symbols to the index of the type of the function
200 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
Sam Cleggd99f6072017-06-12 23:52:44 +0000201 // Maps function symbols to the table element index space. Used
202 // for TABLE_INDEX relocation types (i.e. address taken functions).
Sam Cleggf9edbe92018-01-31 19:28:47 +0000203 DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
Sam Clegg6c899ba2018-02-23 05:08:34 +0000204 // Maps function/global symbols to the (shared) Symbol index space.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000205 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices;
Sam Clegg6c899ba2018-02-23 05:08:34 +0000206 // Maps function/global symbols to the function/global Wasm index space.
207 DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
208 // Maps data symbols to the Wasm segment and offset/size with the segment.
209 DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000210
211 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo>
212 FunctionTypeIndices;
Sam Clegg5e3d33a2017-07-07 02:01:29 +0000213 SmallVector<WasmFunctionType, 4> FunctionTypes;
Sam Clegg7c395942017-09-14 23:07:53 +0000214 SmallVector<WasmGlobal, 4> Globals;
Sam Clegg6c899ba2018-02-23 05:08:34 +0000215 SmallVector<WasmDataSegment, 4> DataSegments;
Sam Cleggcfd44a22018-04-05 17:01:39 +0000216 std::vector<WasmCustomSection> CustomSections;
Sam Clegg9f3fe422018-01-17 19:28:43 +0000217 unsigned NumFunctionImports = 0;
Sam Clegg7c395942017-09-14 23:07:53 +0000218 unsigned NumGlobalImports = 0;
Chandler Carruth7e1c3342018-04-24 20:30:56 +0000219 uint32_t SectionCount = 0;
Dan Gohmand934cb82017-02-24 23:18:00 +0000220
Dan Gohman18eafb62017-02-22 01:23:18 +0000221 // TargetObjectWriter wrappers.
222 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
Sam Cleggae03c1e72017-06-13 18:51:50 +0000223 unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const {
224 return TargetObjectWriter->getRelocType(Target, Fixup);
Dan Gohman18eafb62017-02-22 01:23:18 +0000225 }
226
Sam Clegg2322a932018-04-23 19:16:19 +0000227 void startSection(SectionBookkeeping &Section, unsigned SectionId);
228 void startCustomSection(SectionBookkeeping &Section, StringRef Name);
Dan Gohmand934cb82017-02-24 23:18:00 +0000229 void endSection(SectionBookkeeping &Section);
230
Dan Gohman18eafb62017-02-22 01:23:18 +0000231public:
Lang Hames1301a872017-10-10 01:15:10 +0000232 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
233 raw_pwrite_stream &OS)
234 : MCObjectWriter(OS, /*IsLittleEndian=*/true),
235 TargetObjectWriter(std::move(MOTW)) {}
Dan Gohman18eafb62017-02-22 01:23:18 +0000236
Dan Gohman18eafb62017-02-22 01:23:18 +0000237 ~WasmObjectWriter() override;
238
Dan Gohman0917c9e2018-01-15 17:06:23 +0000239private:
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000240 void reset() override {
241 CodeRelocations.clear();
242 DataRelocations.clear();
243 TypeIndices.clear();
244 SymbolIndices.clear();
Sam Clegg6c899ba2018-02-23 05:08:34 +0000245 WasmIndices.clear();
Sam Cleggf9edbe92018-01-31 19:28:47 +0000246 TableIndices.clear();
Sam Clegg6c899ba2018-02-23 05:08:34 +0000247 DataLocations.clear();
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000248 FunctionTypeIndices.clear();
Sam Clegg5e3d33a2017-07-07 02:01:29 +0000249 FunctionTypes.clear();
Sam Clegg7c395942017-09-14 23:07:53 +0000250 Globals.clear();
Sam Clegg6c899ba2018-02-23 05:08:34 +0000251 DataSegments.clear();
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000252 MCObjectWriter::reset();
Sam Clegg9f3fe422018-01-17 19:28:43 +0000253 NumFunctionImports = 0;
Sam Clegg7c395942017-09-14 23:07:53 +0000254 NumGlobalImports = 0;
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000255 }
256
Dan Gohman18eafb62017-02-22 01:23:18 +0000257 void writeHeader(const MCAssembler &Asm);
258
259 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
260 const MCFragment *Fragment, const MCFixup &Fixup,
Rafael Espindolaceecfe5b2017-07-11 23:56:10 +0000261 MCValue Target, uint64_t &FixedValue) override;
Dan Gohman18eafb62017-02-22 01:23:18 +0000262
263 void executePostLayoutBinding(MCAssembler &Asm,
264 const MCAsmLayout &Layout) override;
265
266 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
Sam Clegg9e15f352017-06-03 02:01:24 +0000267
Sam Cleggb7787fd2017-06-20 04:04:59 +0000268 void writeString(const StringRef Str) {
269 encodeULEB128(Str.size(), getStream());
270 writeBytes(Str);
271 }
272
Sam Clegg9e15f352017-06-03 02:01:24 +0000273 void writeValueType(wasm::ValType Ty) {
Sam Clegg03e101f2018-03-01 18:06:21 +0000274 write8(static_cast<uint8_t>(Ty));
Sam Clegg9e15f352017-06-03 02:01:24 +0000275 }
276
Sam Clegg457fb0b2017-09-15 19:50:44 +0000277 void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes);
Sam Clegg8defa952018-02-12 22:41:29 +0000278 void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
Sam Cleggf950b242017-12-11 23:03:38 +0000279 uint32_t NumElements);
Sam Clegg457fb0b2017-09-15 19:50:44 +0000280 void writeFunctionSection(ArrayRef<WasmFunction> Functions);
Sam Clegg7c395942017-09-14 23:07:53 +0000281 void writeGlobalSection();
Sam Clegg8defa952018-02-12 22:41:29 +0000282 void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
Sam Clegg457fb0b2017-09-15 19:50:44 +0000283 void writeElemSection(ArrayRef<uint32_t> TableElems);
Sam Clegg9e15f352017-06-03 02:01:24 +0000284 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
Sam Clegg457fb0b2017-09-15 19:50:44 +0000285 ArrayRef<WasmFunction> Functions);
Sam Clegg6c899ba2018-02-23 05:08:34 +0000286 void writeDataSection();
Sam Clegg6f08c842018-04-24 18:11:36 +0000287 void writeRelocSection(uint32_t SectionIndex, StringRef Name,
288 ArrayRef<WasmRelocationEntry> Relocations);
Sam Clegg31a2c802017-09-20 21:17:04 +0000289 void writeLinkingMetaDataSection(
Sam Clegg86b4a092018-02-27 23:57:37 +0000290 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
Sam Cleggea7cace2018-01-09 23:43:14 +0000291 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
Sam Clegg6c899ba2018-02-23 05:08:34 +0000292 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
Sam Cleggcfd44a22018-04-05 17:01:39 +0000293 void writeUserCustomSections(ArrayRef<WasmCustomSection> CustomSections);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000294
Sam Clegg7c395942017-09-14 23:07:53 +0000295 uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000296 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
297 uint64_t ContentsOffset);
298
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000299 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
Sam Clegg6f08c842018-04-24 18:11:36 +0000300 uint32_t getFunctionType(const MCSymbolWasm &Symbol);
301 uint32_t registerFunctionType(const MCSymbolWasm &Symbol);
Dan Gohman18eafb62017-02-22 01:23:18 +0000302};
Sam Clegg9e15f352017-06-03 02:01:24 +0000303
Dan Gohman18eafb62017-02-22 01:23:18 +0000304} // end anonymous namespace
305
306WasmObjectWriter::~WasmObjectWriter() {}
307
Dan Gohmand934cb82017-02-24 23:18:00 +0000308// Write out a section header and a patchable section size field.
309void WasmObjectWriter::startSection(SectionBookkeeping &Section,
Sam Clegg2322a932018-04-23 19:16:19 +0000310 unsigned SectionId) {
311 DEBUG(dbgs() << "startSection " << SectionId << "\n");
Sam Clegg03e101f2018-03-01 18:06:21 +0000312 write8(SectionId);
Dan Gohmand934cb82017-02-24 23:18:00 +0000313
314 Section.SizeOffset = getStream().tell();
315
316 // The section size. We don't know the size yet, so reserve enough space
317 // for any 32-bit value; we'll patch it later.
318 encodeULEB128(UINT32_MAX, getStream());
319
320 // The position where the section starts, for measuring its size.
321 Section.ContentsOffset = getStream().tell();
Sam Clegg6f08c842018-04-24 18:11:36 +0000322 Section.Index = SectionCount++;
Sam Clegg2322a932018-04-23 19:16:19 +0000323}
Dan Gohmand934cb82017-02-24 23:18:00 +0000324
Sam Clegg2322a932018-04-23 19:16:19 +0000325void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
326 StringRef Name) {
327 DEBUG(dbgs() << "startCustomSection " << Name << "\n");
328 startSection(Section, wasm::WASM_SEC_CUSTOM);
Dan Gohmand934cb82017-02-24 23:18:00 +0000329 // Custom sections in wasm also have a string identifier.
Sam Clegg2322a932018-04-23 19:16:19 +0000330 writeString(Name);
Dan Gohmand934cb82017-02-24 23:18:00 +0000331}
332
333// Now that the section is complete and we know how big it is, patch up the
334// section size field at the start of the section.
335void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
336 uint64_t Size = getStream().tell() - Section.ContentsOffset;
337 if (uint32_t(Size) != Size)
338 report_fatal_error("section size does not fit in a uint32_t");
339
Sam Cleggb7787fd2017-06-20 04:04:59 +0000340 DEBUG(dbgs() << "endSection size=" << Size << "\n");
Dan Gohmand934cb82017-02-24 23:18:00 +0000341
342 // Write the final section size to the payload_len field, which follows
343 // the section id byte.
344 uint8_t Buffer[16];
Sam Clegg66a99e42017-09-15 20:34:47 +0000345 unsigned SizeLen = encodeULEB128(Size, Buffer, 5);
Dan Gohmand934cb82017-02-24 23:18:00 +0000346 assert(SizeLen == 5);
347 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
348}
349
Dan Gohman18eafb62017-02-22 01:23:18 +0000350// Emit the Wasm header.
351void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
Dan Gohman7ea5adf2017-02-22 18:50:20 +0000352 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic)));
353 writeLE32(wasm::WasmVersion);
Dan Gohman18eafb62017-02-22 01:23:18 +0000354}
355
356void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
357 const MCAsmLayout &Layout) {
358}
359
360void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
361 const MCAsmLayout &Layout,
362 const MCFragment *Fragment,
363 const MCFixup &Fixup, MCValue Target,
Rafael Espindolaceecfe5b2017-07-11 23:56:10 +0000364 uint64_t &FixedValue) {
365 MCAsmBackend &Backend = Asm.getBackend();
366 bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
367 MCFixupKindInfo::FKF_IsPCRel;
Sam Cleggfe6414b2017-06-21 23:46:41 +0000368 const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
Dan Gohmand934cb82017-02-24 23:18:00 +0000369 uint64_t C = Target.getConstant();
370 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
371 MCContext &Ctx = Asm.getContext();
372
Sam Cleggbafe6902017-12-15 00:17:10 +0000373 // The .init_array isn't translated as data, so don't do relocations in it.
374 if (FixupSection.getSectionName().startswith(".init_array"))
375 return;
376
Sam Cleggb7a54692018-02-16 18:06:05 +0000377 // TODO(sbc): Add support for debug sections.
378 if (FixupSection.getKind().isMetadata())
379 return;
380
Dan Gohmand934cb82017-02-24 23:18:00 +0000381 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
382 assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
383 "Should not have constructed this");
384
385 // Let A, B and C being the components of Target and R be the location of
386 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
387 // If it is pcrel, we want to compute (A - B + C - R).
388
389 // In general, Wasm has no relocations for -B. It can only represent (A + C)
390 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
391 // replace B to implement it: (A - R - K + C)
392 if (IsPCRel) {
393 Ctx.reportError(
394 Fixup.getLoc(),
395 "No relocation available to represent this relative expression");
396 return;
397 }
398
399 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
400
401 if (SymB.isUndefined()) {
402 Ctx.reportError(Fixup.getLoc(),
403 Twine("symbol '") + SymB.getName() +
404 "' can not be undefined in a subtraction expression");
405 return;
406 }
407
408 assert(!SymB.isAbsolute() && "Should have been folded");
409 const MCSection &SecB = SymB.getSection();
410 if (&SecB != &FixupSection) {
411 Ctx.reportError(Fixup.getLoc(),
412 "Cannot represent a difference across sections");
413 return;
414 }
415
416 uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
417 uint64_t K = SymBOffset - FixupOffset;
418 IsPCRel = true;
419 C -= K;
420 }
421
422 // We either rejected the fixup or folded B into C at this point.
423 const MCSymbolRefExpr *RefA = Target.getSymA();
424 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
425
Dan Gohmand934cb82017-02-24 23:18:00 +0000426 if (SymA && SymA->isVariable()) {
427 const MCExpr *Expr = SymA->getVariableValue();
Sam Clegg6ad8f192017-07-11 02:21:57 +0000428 const auto *Inner = cast<MCSymbolRefExpr>(Expr);
429 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
430 llvm_unreachable("weakref used in reloc not yet implemented");
Dan Gohmand934cb82017-02-24 23:18:00 +0000431 }
432
433 // Put any constant offset in an addend. Offsets can be negative, and
434 // LLVM expects wrapping, in contrast to wasm's immediates which can't
435 // be negative and don't wrap.
436 FixedValue = 0;
437
Sam Clegg6ad8f192017-07-11 02:21:57 +0000438 if (SymA)
439 SymA->setUsedInReloc();
Dan Gohmand934cb82017-02-24 23:18:00 +0000440
Sam Cleggae03c1e72017-06-13 18:51:50 +0000441 assert(!IsPCRel);
Sam Clegg9d24fb72017-06-16 23:59:10 +0000442 assert(SymA);
443
Sam Cleggae03c1e72017-06-13 18:51:50 +0000444 unsigned Type = getRelocType(Target, Fixup);
445
Dan Gohmand934cb82017-02-24 23:18:00 +0000446 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
Sam Cleggb7787fd2017-06-20 04:04:59 +0000447 DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
Dan Gohmand934cb82017-02-24 23:18:00 +0000448
Sam Cleggb7a54692018-02-16 18:06:05 +0000449 // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required
450 // to be against a named symbol.
451 // TODO(sbc): Add support for relocations against unnamed temporaries such
452 // as those generated by llvm's `blockaddress`.
453 // See: test/MC/WebAssembly/blockaddress.ll
454 if (SymA->getName().empty() && Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
455 report_fatal_error("relocations against un-named temporaries are not yet "
456 "supported by wasm");
457
Sam Clegg12fd3da2017-10-20 21:28:38 +0000458 if (FixupSection.isWasmData())
Dan Gohmand934cb82017-02-24 23:18:00 +0000459 DataRelocations.push_back(Rec);
Sam Clegg12fd3da2017-10-20 21:28:38 +0000460 else if (FixupSection.getKind().isText())
461 CodeRelocations.push_back(Rec);
Sam Cleggb7a54692018-02-16 18:06:05 +0000462 else
Sam Clegg12fd3da2017-10-20 21:28:38 +0000463 llvm_unreachable("unexpected section type");
Dan Gohmand934cb82017-02-24 23:18:00 +0000464}
465
Dan Gohmand934cb82017-02-24 23:18:00 +0000466// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
467// to allow patching.
468static void
469WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
470 uint8_t Buffer[5];
Sam Clegg66a99e42017-09-15 20:34:47 +0000471 unsigned SizeLen = encodeULEB128(X, Buffer, 5);
Dan Gohmand934cb82017-02-24 23:18:00 +0000472 assert(SizeLen == 5);
473 Stream.pwrite((char *)Buffer, SizeLen, Offset);
474}
475
476// Write X as an signed LEB value at offset Offset in Stream, padded
477// to allow patching.
478static void
479WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
480 uint8_t Buffer[5];
Sam Clegg66a99e42017-09-15 20:34:47 +0000481 unsigned SizeLen = encodeSLEB128(X, Buffer, 5);
Dan Gohmand934cb82017-02-24 23:18:00 +0000482 assert(SizeLen == 5);
483 Stream.pwrite((char *)Buffer, SizeLen, Offset);
484}
485
486// Write X as a plain integer value at offset Offset in Stream.
487static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
488 uint8_t Buffer[4];
489 support::endian::write32le(Buffer, X);
490 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
491}
492
Sam Cleggaff1c4d2017-09-15 19:22:01 +0000493static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) {
494 if (Symbol.isVariable()) {
495 const MCExpr *Expr = Symbol.getVariableValue();
496 auto *Inner = cast<MCSymbolRefExpr>(Expr);
497 return cast<MCSymbolWasm>(&Inner->getSymbol());
498 }
499 return &Symbol;
500}
501
Dan Gohmand934cb82017-02-24 23:18:00 +0000502// Compute a value to write into the code at the location covered
Sam Clegg60ec3032018-01-23 01:23:17 +0000503// by RelEntry. This value isn't used by the static linker; it just serves
504// to make the object format more readable and more likely to be directly
505// useable.
Sam Clegg7c395942017-09-14 23:07:53 +0000506uint32_t
507WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
Sam Clegg60ec3032018-01-23 01:23:17 +0000508 switch (RelEntry.Type) {
509 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
Sam Cleggf9edbe92018-01-31 19:28:47 +0000510 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
511 // Provisional value is table address of the resolved symbol itself
512 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol);
513 assert(Sym->isFunction());
514 return TableIndices[Sym];
515 }
Sam Clegg60ec3032018-01-23 01:23:17 +0000516 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
Sam Clegg6c899ba2018-02-23 05:08:34 +0000517 // Provisional value is same as the index
Sam Clegg60ec3032018-01-23 01:23:17 +0000518 return getRelocationIndexValue(RelEntry);
Sam Clegg6c899ba2018-02-23 05:08:34 +0000519 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
520 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
521 // Provisional value is function/global Wasm index
522 if (!WasmIndices.count(RelEntry.Symbol))
523 report_fatal_error("symbol not found in wasm index space: " +
524 RelEntry.Symbol->getName());
525 return WasmIndices[RelEntry.Symbol];
Sam Clegg60ec3032018-01-23 01:23:17 +0000526 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
527 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
528 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: {
Sam Cleggf9edbe92018-01-31 19:28:47 +0000529 // Provisional value is address of the global
Sam Clegg60ec3032018-01-23 01:23:17 +0000530 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol);
531 // For undefined symbols, use zero
532 if (!Sym->isDefined())
533 return 0;
Sam Clegg6c899ba2018-02-23 05:08:34 +0000534 const wasm::WasmDataReference &Ref = DataLocations[Sym];
535 const WasmDataSegment &Segment = DataSegments[Ref.Segment];
Sam Clegg60ec3032018-01-23 01:23:17 +0000536 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
Sam Clegg6c899ba2018-02-23 05:08:34 +0000537 return Segment.Offset + Ref.Offset + RelEntry.Addend;
Sam Clegg60ec3032018-01-23 01:23:17 +0000538 }
539 default:
540 llvm_unreachable("invalid relocation type");
541 }
Dan Gohmand934cb82017-02-24 23:18:00 +0000542}
543
Sam Clegg759631c2017-09-15 20:54:59 +0000544static void addData(SmallVectorImpl<char> &DataBytes,
Sam Clegg63ebb812017-09-29 16:50:08 +0000545 MCSectionWasm &DataSection) {
Sam Clegg759631c2017-09-15 20:54:59 +0000546 DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
547
Sam Clegg63ebb812017-09-29 16:50:08 +0000548 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
549
Sam Clegg759631c2017-09-15 20:54:59 +0000550 for (const MCFragment &Frag : DataSection) {
551 if (Frag.hasInstructions())
552 report_fatal_error("only data supported in data sections");
553
554 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
555 if (Align->getValueSize() != 1)
556 report_fatal_error("only byte values supported for alignment");
557 // If nops are requested, use zeros, as this is the data section.
558 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
559 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
560 Align->getAlignment()),
561 DataBytes.size() +
562 Align->getMaxBytesToEmit());
563 DataBytes.resize(Size, Value);
564 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
Rafael Espindolad707c372018-01-09 22:48:37 +0000565 int64_t Size;
566 if (!Fill->getSize().evaluateAsAbsolute(Size))
567 llvm_unreachable("The fill should be an assembler constant");
568 DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
Sam Clegg759631c2017-09-15 20:54:59 +0000569 } else {
570 const auto &DataFrag = cast<MCDataFragment>(Frag);
571 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
572
573 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
574 }
575 }
576
577 DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
578}
579
Sam Clegg60ec3032018-01-23 01:23:17 +0000580uint32_t
581WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
582 if (RelEntry.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) {
Sam Cleggb7787fd2017-06-20 04:04:59 +0000583 if (!TypeIndices.count(RelEntry.Symbol))
Sam Clegg5e3d33a2017-07-07 02:01:29 +0000584 report_fatal_error("symbol not found in type index space: " +
Sam Cleggb7787fd2017-06-20 04:04:59 +0000585 RelEntry.Symbol->getName());
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000586 return TypeIndices[RelEntry.Symbol];
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000587 }
Sam Clegg60ec3032018-01-23 01:23:17 +0000588
589 if (!SymbolIndices.count(RelEntry.Symbol))
Sam Clegg6c899ba2018-02-23 05:08:34 +0000590 report_fatal_error("symbol not found in symbol index space: " +
Sam Clegg60ec3032018-01-23 01:23:17 +0000591 RelEntry.Symbol->getName());
592 return SymbolIndices[RelEntry.Symbol];
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000593}
594
Dan Gohmand934cb82017-02-24 23:18:00 +0000595// Apply the portions of the relocation records that we can handle ourselves
596// directly.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000597void WasmObjectWriter::applyRelocations(
598 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
599 raw_pwrite_stream &Stream = getStream();
Dan Gohmand934cb82017-02-24 23:18:00 +0000600 for (const WasmRelocationEntry &RelEntry : Relocations) {
601 uint64_t Offset = ContentsOffset +
602 RelEntry.FixupSection->getSectionOffset() +
603 RelEntry.Offset;
Dan Gohmand934cb82017-02-24 23:18:00 +0000604
Sam Cleggb7787fd2017-06-20 04:04:59 +0000605 DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
Sam Clegg60ec3032018-01-23 01:23:17 +0000606 uint32_t Value = getProvisionalValue(RelEntry);
607
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000608 switch (RelEntry.Type) {
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000609 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
Sam Clegg9d24fb72017-06-16 23:59:10 +0000610 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
Sam Clegg60ec3032018-01-23 01:23:17 +0000611 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
612 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
Dan Gohmand934cb82017-02-24 23:18:00 +0000613 WritePatchableLEB(Stream, Value, Offset);
614 break;
Sam Clegg60ec3032018-01-23 01:23:17 +0000615 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
616 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
Dan Gohmand934cb82017-02-24 23:18:00 +0000617 WriteI32(Stream, Value, Offset);
618 break;
Sam Clegg60ec3032018-01-23 01:23:17 +0000619 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
620 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
621 WritePatchableSLEB(Stream, Value, Offset);
622 break;
Dan Gohmand934cb82017-02-24 23:18:00 +0000623 default:
Sam Clegg9d24fb72017-06-16 23:59:10 +0000624 llvm_unreachable("invalid relocation type");
Dan Gohmand934cb82017-02-24 23:18:00 +0000625 }
626 }
Dan Gohman18eafb62017-02-22 01:23:18 +0000627}
628
Sam Clegg9e15f352017-06-03 02:01:24 +0000629void WasmObjectWriter::writeTypeSection(
Sam Clegg457fb0b2017-09-15 19:50:44 +0000630 ArrayRef<WasmFunctionType> FunctionTypes) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000631 if (FunctionTypes.empty())
632 return;
633
634 SectionBookkeeping Section;
635 startSection(Section, wasm::WASM_SEC_TYPE);
636
637 encodeULEB128(FunctionTypes.size(), getStream());
638
639 for (const WasmFunctionType &FuncTy : FunctionTypes) {
Sam Clegg03e101f2018-03-01 18:06:21 +0000640 write8(wasm::WASM_TYPE_FUNC);
Sam Clegg9e15f352017-06-03 02:01:24 +0000641 encodeULEB128(FuncTy.Params.size(), getStream());
642 for (wasm::ValType Ty : FuncTy.Params)
643 writeValueType(Ty);
644 encodeULEB128(FuncTy.Returns.size(), getStream());
645 for (wasm::ValType Ty : FuncTy.Returns)
646 writeValueType(Ty);
647 }
648
649 endSection(Section);
650}
651
Sam Clegg8defa952018-02-12 22:41:29 +0000652void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
Sam Cleggf950b242017-12-11 23:03:38 +0000653 uint32_t DataSize,
654 uint32_t NumElements) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000655 if (Imports.empty())
656 return;
657
Sam Cleggf950b242017-12-11 23:03:38 +0000658 uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
659
Sam Clegg9e15f352017-06-03 02:01:24 +0000660 SectionBookkeeping Section;
661 startSection(Section, wasm::WASM_SEC_IMPORT);
662
663 encodeULEB128(Imports.size(), getStream());
Sam Clegg8defa952018-02-12 22:41:29 +0000664 for (const wasm::WasmImport &Import : Imports) {
665 writeString(Import.Module);
666 writeString(Import.Field);
Sam Clegg03e101f2018-03-01 18:06:21 +0000667 write8(Import.Kind);
Sam Clegg9e15f352017-06-03 02:01:24 +0000668
669 switch (Import.Kind) {
670 case wasm::WASM_EXTERNAL_FUNCTION:
Sam Clegg8defa952018-02-12 22:41:29 +0000671 encodeULEB128(Import.SigIndex, getStream());
Sam Clegg9e15f352017-06-03 02:01:24 +0000672 break;
673 case wasm::WASM_EXTERNAL_GLOBAL:
Sam Clegg03e101f2018-03-01 18:06:21 +0000674 write8(Import.Global.Type);
675 write8(Import.Global.Mutable ? 1 : 0);
Sam Clegg9e15f352017-06-03 02:01:24 +0000676 break;
Sam Cleggf950b242017-12-11 23:03:38 +0000677 case wasm::WASM_EXTERNAL_MEMORY:
678 encodeULEB128(0, getStream()); // flags
679 encodeULEB128(NumPages, getStream()); // initial
680 break;
681 case wasm::WASM_EXTERNAL_TABLE:
Sam Clegg03e101f2018-03-01 18:06:21 +0000682 write8(Import.Table.ElemType);
Sam Cleggf950b242017-12-11 23:03:38 +0000683 encodeULEB128(0, getStream()); // flags
684 encodeULEB128(NumElements, getStream()); // initial
685 break;
Sam Clegg9e15f352017-06-03 02:01:24 +0000686 default:
687 llvm_unreachable("unsupported import kind");
688 }
689 }
690
691 endSection(Section);
692}
693
Sam Clegg457fb0b2017-09-15 19:50:44 +0000694void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000695 if (Functions.empty())
696 return;
697
698 SectionBookkeeping Section;
699 startSection(Section, wasm::WASM_SEC_FUNCTION);
700
701 encodeULEB128(Functions.size(), getStream());
702 for (const WasmFunction &Func : Functions)
703 encodeULEB128(Func.Type, getStream());
704
705 endSection(Section);
706}
707
Sam Clegg7c395942017-09-14 23:07:53 +0000708void WasmObjectWriter::writeGlobalSection() {
Sam Clegg9e15f352017-06-03 02:01:24 +0000709 if (Globals.empty())
710 return;
711
712 SectionBookkeeping Section;
713 startSection(Section, wasm::WASM_SEC_GLOBAL);
714
715 encodeULEB128(Globals.size(), getStream());
716 for (const WasmGlobal &Global : Globals) {
Sam Clegg6e7f1822018-01-31 19:50:14 +0000717 writeValueType(static_cast<wasm::ValType>(Global.Type.Type));
718 write8(Global.Type.Mutable);
Sam Clegg9e15f352017-06-03 02:01:24 +0000719
Sam Clegg6e7f1822018-01-31 19:50:14 +0000720 write8(wasm::WASM_OPCODE_I32_CONST);
721 encodeSLEB128(Global.InitialValue, getStream());
Sam Clegg9e15f352017-06-03 02:01:24 +0000722 write8(wasm::WASM_OPCODE_END);
723 }
724
725 endSection(Section);
726}
727
Sam Clegg8defa952018-02-12 22:41:29 +0000728void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000729 if (Exports.empty())
730 return;
731
732 SectionBookkeeping Section;
733 startSection(Section, wasm::WASM_SEC_EXPORT);
734
735 encodeULEB128(Exports.size(), getStream());
Sam Clegg8defa952018-02-12 22:41:29 +0000736 for (const wasm::WasmExport &Export : Exports) {
737 writeString(Export.Name);
Sam Clegg03e101f2018-03-01 18:06:21 +0000738 write8(Export.Kind);
Sam Clegg9e15f352017-06-03 02:01:24 +0000739 encodeULEB128(Export.Index, getStream());
740 }
741
742 endSection(Section);
743}
744
Sam Clegg457fb0b2017-09-15 19:50:44 +0000745void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000746 if (TableElems.empty())
747 return;
748
749 SectionBookkeeping Section;
750 startSection(Section, wasm::WASM_SEC_ELEM);
751
752 encodeULEB128(1, getStream()); // number of "segments"
753 encodeULEB128(0, getStream()); // the table index
754
755 // init expr for starting offset
756 write8(wasm::WASM_OPCODE_I32_CONST);
Sam Clegg30e1bbc2018-01-19 18:57:01 +0000757 encodeSLEB128(kInitialTableOffset, getStream());
Sam Clegg9e15f352017-06-03 02:01:24 +0000758 write8(wasm::WASM_OPCODE_END);
759
760 encodeULEB128(TableElems.size(), getStream());
761 for (uint32_t Elem : TableElems)
762 encodeULEB128(Elem, getStream());
763
764 endSection(Section);
765}
766
Sam Clegg457fb0b2017-09-15 19:50:44 +0000767void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
768 const MCAsmLayout &Layout,
769 ArrayRef<WasmFunction> Functions) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000770 if (Functions.empty())
771 return;
772
773 SectionBookkeeping Section;
774 startSection(Section, wasm::WASM_SEC_CODE);
Sam Clegg6f08c842018-04-24 18:11:36 +0000775 CodeSectionIndex = Section.Index;
Sam Clegg9e15f352017-06-03 02:01:24 +0000776
777 encodeULEB128(Functions.size(), getStream());
778
779 for (const WasmFunction &Func : Functions) {
Sam Cleggfe6414b2017-06-21 23:46:41 +0000780 auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection());
Sam Clegg9e15f352017-06-03 02:01:24 +0000781
Sam Clegg9e15f352017-06-03 02:01:24 +0000782 int64_t Size = 0;
783 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
784 report_fatal_error(".size expression must be evaluatable");
785
786 encodeULEB128(Size, getStream());
Sam Cleggfe6414b2017-06-21 23:46:41 +0000787 FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset);
Sam Clegg9e15f352017-06-03 02:01:24 +0000788 Asm.writeSectionData(&FuncSection, Layout);
789 }
790
Sam Clegg9e15f352017-06-03 02:01:24 +0000791 // Apply fixups.
Sam Cleggacd7d2b2017-06-06 19:15:05 +0000792 applyRelocations(CodeRelocations, Section.ContentsOffset);
Sam Clegg9e15f352017-06-03 02:01:24 +0000793
794 endSection(Section);
795}
796
Sam Clegg6c899ba2018-02-23 05:08:34 +0000797void WasmObjectWriter::writeDataSection() {
798 if (DataSegments.empty())
Sam Clegg7c395942017-09-14 23:07:53 +0000799 return;
Sam Clegg9e15f352017-06-03 02:01:24 +0000800
801 SectionBookkeeping Section;
802 startSection(Section, wasm::WASM_SEC_DATA);
Sam Clegg6f08c842018-04-24 18:11:36 +0000803 DataSectionIndex = Section.Index;
Sam Clegg9e15f352017-06-03 02:01:24 +0000804
Sam Clegg6c899ba2018-02-23 05:08:34 +0000805 encodeULEB128(DataSegments.size(), getStream()); // count
Sam Clegg7c395942017-09-14 23:07:53 +0000806
Sam Clegg6c899ba2018-02-23 05:08:34 +0000807 for (const WasmDataSegment &Segment : DataSegments) {
Sam Clegg7c395942017-09-14 23:07:53 +0000808 encodeULEB128(0, getStream()); // memory index
809 write8(wasm::WASM_OPCODE_I32_CONST);
810 encodeSLEB128(Segment.Offset, getStream()); // offset
811 write8(wasm::WASM_OPCODE_END);
812 encodeULEB128(Segment.Data.size(), getStream()); // size
813 Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset);
814 writeBytes(Segment.Data); // data
815 }
Sam Clegg9e15f352017-06-03 02:01:24 +0000816
817 // Apply fixups.
Sam Clegg7c395942017-09-14 23:07:53 +0000818 applyRelocations(DataRelocations, Section.ContentsOffset);
Sam Clegg9e15f352017-06-03 02:01:24 +0000819
820 endSection(Section);
Sam Clegg9e15f352017-06-03 02:01:24 +0000821}
822
Sam Clegg6f08c842018-04-24 18:11:36 +0000823void WasmObjectWriter::writeRelocSection(
824 uint32_t SectionIndex, StringRef Name,
825 ArrayRef<WasmRelocationEntry> Relocations) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000826 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
827 // for descriptions of the reloc sections.
828
Sam Clegg6f08c842018-04-24 18:11:36 +0000829 if (Relocations.empty())
Sam Clegg9e15f352017-06-03 02:01:24 +0000830 return;
831
832 SectionBookkeeping Section;
Sam Clegg6f08c842018-04-24 18:11:36 +0000833 startCustomSection(Section, std::string("reloc.") + Name.str());
Sam Clegg9e15f352017-06-03 02:01:24 +0000834
Sam Clegg6f08c842018-04-24 18:11:36 +0000835 raw_pwrite_stream &Stream = getStream();
Sam Clegg9e15f352017-06-03 02:01:24 +0000836
Sam Clegg6f08c842018-04-24 18:11:36 +0000837 encodeULEB128(SectionIndex, Stream);
838 encodeULEB128(Relocations.size(), Stream);
839 for (const WasmRelocationEntry& RelEntry : Relocations) {
840 uint64_t Offset = RelEntry.Offset +
841 RelEntry.FixupSection->getSectionOffset();
842 uint32_t Index = getRelocationIndexValue(RelEntry);
Sam Clegg9e15f352017-06-03 02:01:24 +0000843
Sam Clegg6f08c842018-04-24 18:11:36 +0000844 write8(RelEntry.Type);
845 encodeULEB128(Offset, Stream);
846 encodeULEB128(Index, Stream);
847 if (RelEntry.hasAddend())
848 encodeSLEB128(RelEntry.Addend, Stream);
849 }
Sam Clegg9e15f352017-06-03 02:01:24 +0000850
851 endSection(Section);
852}
853
854void WasmObjectWriter::writeLinkingMetaDataSection(
Sam Clegg86b4a092018-02-27 23:57:37 +0000855 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
Sam Cleggea7cace2018-01-09 23:43:14 +0000856 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
Sam Clegg6c899ba2018-02-23 05:08:34 +0000857 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
Sam Clegg9e15f352017-06-03 02:01:24 +0000858 SectionBookkeeping Section;
Sam Clegg2322a932018-04-23 19:16:19 +0000859 startCustomSection(Section, "linking");
Sam Clegg6bb5a412018-04-26 18:15:32 +0000860 encodeULEB128(wasm::WasmMetadataVersion, getStream());
Sam Clegg9e15f352017-06-03 02:01:24 +0000861
Sam Clegg6bb5a412018-04-26 18:15:32 +0000862 SectionBookkeeping SubSection;
Sam Clegg6c899ba2018-02-23 05:08:34 +0000863 if (SymbolInfos.size() != 0) {
864 startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
865 encodeULEB128(SymbolInfos.size(), getStream());
866 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
867 encodeULEB128(Sym.Kind, getStream());
868 encodeULEB128(Sym.Flags, getStream());
869 switch (Sym.Kind) {
870 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
871 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
872 encodeULEB128(Sym.ElementIndex, getStream());
873 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0)
874 writeString(Sym.Name);
875 break;
876 case wasm::WASM_SYMBOL_TYPE_DATA:
877 writeString(Sym.Name);
878 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
879 encodeULEB128(Sym.DataRef.Segment, getStream());
880 encodeULEB128(Sym.DataRef.Offset, getStream());
881 encodeULEB128(Sym.DataRef.Size, getStream());
882 }
883 break;
884 default:
885 llvm_unreachable("unexpected kind");
886 }
Sam Cleggb7787fd2017-06-20 04:04:59 +0000887 }
888 endSection(SubSection);
889 }
Sam Clegg9e15f352017-06-03 02:01:24 +0000890
Sam Clegg6c899ba2018-02-23 05:08:34 +0000891 if (DataSegments.size()) {
Sam Clegg63ebb812017-09-29 16:50:08 +0000892 startSection(SubSection, wasm::WASM_SEGMENT_INFO);
Sam Clegg6c899ba2018-02-23 05:08:34 +0000893 encodeULEB128(DataSegments.size(), getStream());
894 for (const WasmDataSegment &Segment : DataSegments) {
Sam Cleggd95ed952017-09-20 19:03:35 +0000895 writeString(Segment.Name);
Sam Clegg63ebb812017-09-29 16:50:08 +0000896 encodeULEB128(Segment.Alignment, getStream());
897 encodeULEB128(Segment.Flags, getStream());
898 }
Sam Cleggd95ed952017-09-20 19:03:35 +0000899 endSection(SubSection);
900 }
901
Sam Cleggbafe6902017-12-15 00:17:10 +0000902 if (!InitFuncs.empty()) {
903 startSection(SubSection, wasm::WASM_INIT_FUNCS);
904 encodeULEB128(InitFuncs.size(), getStream());
905 for (auto &StartFunc : InitFuncs) {
906 encodeULEB128(StartFunc.first, getStream()); // priority
907 encodeULEB128(StartFunc.second, getStream()); // function index
908 }
909 endSection(SubSection);
910 }
911
Sam Cleggea7cace2018-01-09 23:43:14 +0000912 if (Comdats.size()) {
913 startSection(SubSection, wasm::WASM_COMDAT_INFO);
914 encodeULEB128(Comdats.size(), getStream());
915 for (const auto &C : Comdats) {
916 writeString(C.first);
917 encodeULEB128(0, getStream()); // flags for future use
918 encodeULEB128(C.second.size(), getStream());
919 for (const WasmComdatEntry &Entry : C.second) {
920 encodeULEB128(Entry.Kind, getStream());
921 encodeULEB128(Entry.Index, getStream());
922 }
923 }
924 endSection(SubSection);
925 }
926
Sam Clegg9e15f352017-06-03 02:01:24 +0000927 endSection(Section);
928}
929
Sam Cleggcfd44a22018-04-05 17:01:39 +0000930void WasmObjectWriter::writeUserCustomSections(
931 ArrayRef<WasmCustomSection> CustomSections) {
932 for (const auto &CustomSection : CustomSections) {
933 SectionBookkeeping Section;
Sam Clegg2322a932018-04-23 19:16:19 +0000934 startCustomSection(Section, CustomSection.Name);
Sam Cleggcfd44a22018-04-05 17:01:39 +0000935 writeBytes(CustomSection.Contents);
936 endSection(Section);
937 }
938}
939
Sam Clegg5e3d33a2017-07-07 02:01:29 +0000940uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) {
941 assert(Symbol.isFunction());
942 assert(TypeIndices.count(&Symbol));
943 return TypeIndices[&Symbol];
944}
945
946uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) {
947 assert(Symbol.isFunction());
948
949 WasmFunctionType F;
Sam Cleggaff1c4d2017-09-15 19:22:01 +0000950 const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol);
951 F.Returns = ResolvedSym->getReturns();
952 F.Params = ResolvedSym->getParams();
Sam Clegg5e3d33a2017-07-07 02:01:29 +0000953
954 auto Pair =
955 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
956 if (Pair.second)
957 FunctionTypes.push_back(F);
958 TypeIndices[&Symbol] = Pair.first->second;
959
960 DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n");
961 DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
962 return Pair.first->second;
963}
964
Dan Gohman18eafb62017-02-22 01:23:18 +0000965void WasmObjectWriter::writeObject(MCAssembler &Asm,
966 const MCAsmLayout &Layout) {
Sam Cleggb7787fd2017-06-20 04:04:59 +0000967 DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
Dan Gohman82607f52017-02-24 23:46:05 +0000968 MCContext &Ctx = Asm.getContext();
Dan Gohmand934cb82017-02-24 23:18:00 +0000969
970 // Collect information from the available symbols.
Dan Gohmand934cb82017-02-24 23:18:00 +0000971 SmallVector<WasmFunction, 4> Functions;
972 SmallVector<uint32_t, 4> TableElems;
Sam Clegg8defa952018-02-12 22:41:29 +0000973 SmallVector<wasm::WasmImport, 4> Imports;
974 SmallVector<wasm::WasmExport, 4> Exports;
Sam Clegg6c899ba2018-02-23 05:08:34 +0000975 SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
Sam Cleggbafe6902017-12-15 00:17:10 +0000976 SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
Sam Cleggea7cace2018-01-09 23:43:14 +0000977 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
Sam Clegg7c395942017-09-14 23:07:53 +0000978 uint32_t DataSize = 0;
Dan Gohmand934cb82017-02-24 23:18:00 +0000979
Sam Cleggf950b242017-12-11 23:03:38 +0000980 // For now, always emit the memory import, since loads and stores are not
981 // valid without it. In the future, we could perhaps be more clever and omit
982 // it if there are no loads or stores.
983 MCSymbolWasm *MemorySym =
984 cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory"));
Sam Clegg8defa952018-02-12 22:41:29 +0000985 wasm::WasmImport MemImport;
986 MemImport.Module = MemorySym->getModuleName();
987 MemImport.Field = MemorySym->getName();
Sam Cleggf950b242017-12-11 23:03:38 +0000988 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
989 Imports.push_back(MemImport);
990
991 // For now, always emit the table section, since indirect calls are not
992 // valid without it. In the future, we could perhaps be more clever and omit
993 // it if there are no indirect calls.
994 MCSymbolWasm *TableSym =
995 cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table"));
Sam Clegg8defa952018-02-12 22:41:29 +0000996 wasm::WasmImport TableImport;
997 TableImport.Module = TableSym->getModuleName();
998 TableImport.Field = TableSym->getName();
Sam Cleggf950b242017-12-11 23:03:38 +0000999 TableImport.Kind = wasm::WASM_EXTERNAL_TABLE;
Sam Clegg8defa952018-02-12 22:41:29 +00001000 TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC;
Sam Cleggf950b242017-12-11 23:03:38 +00001001 Imports.push_back(TableImport);
1002
Nicholas Wilson586320c2018-02-28 17:19:48 +00001003 // Populate FunctionTypeIndices, and Imports and WasmIndices for undefined
1004 // symbols. This must be done before populating WasmIndices for defined
1005 // symbols.
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001006 for (const MCSymbol &S : Asm.symbols()) {
1007 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1008
1009 // Register types for all functions, including those with private linkage
Sam Clegg9f3fe422018-01-17 19:28:43 +00001010 // (because wasm always needs a type signature).
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001011 if (WS.isFunction())
1012 registerFunctionType(WS);
1013
1014 if (WS.isTemporary())
1015 continue;
1016
1017 // If the symbol is not defined in this translation unit, import it.
Sam Clegg6c899ba2018-02-23 05:08:34 +00001018 if (!WS.isDefined() && !WS.isComdat()) {
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001019 if (WS.isFunction()) {
Sam Clegg6c899ba2018-02-23 05:08:34 +00001020 wasm::WasmImport Import;
1021 Import.Module = WS.getModuleName();
1022 Import.Field = WS.getName();
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001023 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
Sam Clegg8defa952018-02-12 22:41:29 +00001024 Import.SigIndex = getFunctionType(WS);
Sam Clegg6c899ba2018-02-23 05:08:34 +00001025 Imports.push_back(Import);
1026 WasmIndices[&WS] = NumFunctionImports++;
1027 } else if (WS.isGlobal()) {
Nicholas Wilson15f349f2018-03-09 16:30:44 +00001028 if (WS.isWeak())
1029 report_fatal_error("undefined global symbol cannot be weak");
1030
Sam Clegg6c899ba2018-02-23 05:08:34 +00001031 wasm::WasmImport Import;
1032 Import.Module = WS.getModuleName();
1033 Import.Field = WS.getName();
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001034 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
Sam Clegg6c899ba2018-02-23 05:08:34 +00001035 Import.Global = WS.getGlobalType();
1036 Imports.push_back(Import);
1037 WasmIndices[&WS] = NumGlobalImports++;
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001038 }
Dan Gohman32ce5ca2017-12-05 18:29:48 +00001039 }
1040 }
1041
Nicholas Wilson586320c2018-02-28 17:19:48 +00001042 // Populate DataSegments, which must be done before populating DataLocations.
Sam Clegg759631c2017-09-15 20:54:59 +00001043 for (MCSection &Sec : Asm) {
1044 auto &Section = static_cast<MCSectionWasm &>(Sec);
Sam Cleggcfd44a22018-04-05 17:01:39 +00001045
1046 if (cast<MCSectionWasm>(Sec).getSectionName().startswith(
1047 ".custom_section.")) {
1048 if (Section.getFragmentList().empty())
1049 continue;
1050 if (Section.getFragmentList().size() != 1)
1051 report_fatal_error(
1052 "only one .custom_section section fragment supported");
1053 const MCFragment &Frag = *Section.begin();
1054 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1055 report_fatal_error("only data supported in .custom_section section");
1056 const auto &DataFrag = cast<MCDataFragment>(Frag);
1057 if (!DataFrag.getFixups().empty())
1058 report_fatal_error("fixups not supported in .custom_section section");
1059 StringRef UserName = Section.getSectionName().substr(16);
1060 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1061 CustomSections.push_back(WasmCustomSection(UserName, Contents));
1062 continue;
1063 }
1064
Sam Clegg12fd3da2017-10-20 21:28:38 +00001065 if (!Section.isWasmData())
Sam Clegg759631c2017-09-15 20:54:59 +00001066 continue;
1067
Sam Cleggbafe6902017-12-15 00:17:10 +00001068 // .init_array sections are handled specially elsewhere.
1069 if (cast<MCSectionWasm>(Sec).getSectionName().startswith(".init_array"))
1070 continue;
1071
Sam Clegg329e76d2018-01-31 04:21:44 +00001072 uint32_t SegmentIndex = DataSegments.size();
Sam Clegg759631c2017-09-15 20:54:59 +00001073 DataSize = alignTo(DataSize, Section.getAlignment());
1074 DataSegments.emplace_back();
1075 WasmDataSegment &Segment = DataSegments.back();
Sam Cleggd95ed952017-09-20 19:03:35 +00001076 Segment.Name = Section.getSectionName();
Sam Clegg759631c2017-09-15 20:54:59 +00001077 Segment.Offset = DataSize;
1078 Segment.Section = &Section;
Sam Clegg63ebb812017-09-29 16:50:08 +00001079 addData(Segment.Data, Section);
1080 Segment.Alignment = Section.getAlignment();
1081 Segment.Flags = 0;
Sam Clegg759631c2017-09-15 20:54:59 +00001082 DataSize += Segment.Data.size();
Sam Clegg6c899ba2018-02-23 05:08:34 +00001083 Section.setSegmentIndex(SegmentIndex);
Sam Cleggea7cace2018-01-09 23:43:14 +00001084
1085 if (const MCSymbolWasm *C = Section.getGroup()) {
1086 Comdats[C->getName()].emplace_back(
Sam Clegg329e76d2018-01-31 04:21:44 +00001087 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
Sam Cleggea7cace2018-01-09 23:43:14 +00001088 }
Sam Clegg759631c2017-09-15 20:54:59 +00001089 }
1090
Nicholas Wilson586320c2018-02-28 17:19:48 +00001091 // Populate WasmIndices and DataLocations for defined symbols.
Dan Gohmand934cb82017-02-24 23:18:00 +00001092 for (const MCSymbol &S : Asm.symbols()) {
1093 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1094 // or used in relocations.
1095 if (S.isTemporary() && S.getName().empty())
1096 continue;
Sam Cleggb7787fd2017-06-20 04:04:59 +00001097
Dan Gohmand934cb82017-02-24 23:18:00 +00001098 const auto &WS = static_cast<const MCSymbolWasm &>(S);
Sam Cleggb7787fd2017-06-20 04:04:59 +00001099 DEBUG(dbgs() << "MCSymbol: '" << S << "'"
Sam Clegg329e76d2018-01-31 04:21:44 +00001100 << " isDefined=" << S.isDefined()
1101 << " isExternal=" << S.isExternal()
1102 << " isTemporary=" << S.isTemporary()
Sam Cleggb7787fd2017-06-20 04:04:59 +00001103 << " isFunction=" << WS.isFunction()
1104 << " isWeak=" << WS.isWeak()
Sam Clegga2b35da2017-12-03 01:19:23 +00001105 << " isHidden=" << WS.isHidden()
Sam Cleggb7787fd2017-06-20 04:04:59 +00001106 << " isVariable=" << WS.isVariable() << "\n");
1107
Sam Clegg5e3d33a2017-07-07 02:01:29 +00001108 if (WS.isVariable())
1109 continue;
Sam Clegg6c899ba2018-02-23 05:08:34 +00001110 if (WS.isComdat() && !WS.isDefined())
1111 continue;
Sam Cleggb7787fd2017-06-20 04:04:59 +00001112
Dan Gohmand934cb82017-02-24 23:18:00 +00001113 if (WS.isFunction()) {
Sam Clegg6c899ba2018-02-23 05:08:34 +00001114 unsigned Index;
Sam Cleggcd65f692018-01-11 23:59:16 +00001115 if (WS.isDefined()) {
Sam Cleggb7787fd2017-06-20 04:04:59 +00001116 if (WS.getOffset() != 0)
1117 report_fatal_error(
1118 "function sections must contain one function each");
1119
1120 if (WS.getSize() == 0)
1121 report_fatal_error(
1122 "function symbols must have a size set with .size");
1123
Sam Clegg6c899ba2018-02-23 05:08:34 +00001124 // A definition. Write out the function body.
Sam Clegg9f3fe422018-01-17 19:28:43 +00001125 Index = NumFunctionImports + Functions.size();
Dan Gohmand934cb82017-02-24 23:18:00 +00001126 WasmFunction Func;
Sam Clegg5e3d33a2017-07-07 02:01:29 +00001127 Func.Type = getFunctionType(WS);
Dan Gohmand934cb82017-02-24 23:18:00 +00001128 Func.Sym = &WS;
Sam Clegg6c899ba2018-02-23 05:08:34 +00001129 WasmIndices[&WS] = Index;
Dan Gohmand934cb82017-02-24 23:18:00 +00001130 Functions.push_back(Func);
Sam Clegg6c899ba2018-02-23 05:08:34 +00001131
1132 auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
1133 if (const MCSymbolWasm *C = Section.getGroup()) {
1134 Comdats[C->getName()].emplace_back(
1135 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
1136 }
Dan Gohmand934cb82017-02-24 23:18:00 +00001137 } else {
1138 // An import; the index was assigned above.
Sam Clegg6c899ba2018-02-23 05:08:34 +00001139 Index = WasmIndices.find(&WS)->second;
Dan Gohmand934cb82017-02-24 23:18:00 +00001140 }
1141
Sam Clegg5e3d33a2017-07-07 02:01:29 +00001142 DEBUG(dbgs() << " -> function index: " << Index << "\n");
Sam Clegg6c899ba2018-02-23 05:08:34 +00001143 } else if (WS.isData()) {
Sam Cleggc38e9472017-06-02 01:05:24 +00001144 if (WS.isTemporary() && !WS.getSize())
1145 continue;
Dan Gohmand934cb82017-02-24 23:18:00 +00001146
Sam Clegg6c899ba2018-02-23 05:08:34 +00001147 if (!WS.isDefined()) {
1148 DEBUG(dbgs() << " -> segment index: -1");
Sam Cleggfe6414b2017-06-21 23:46:41 +00001149 continue;
Sam Clegg6c899ba2018-02-23 05:08:34 +00001150 }
Sam Cleggc38e9472017-06-02 01:05:24 +00001151
Sam Cleggfe6414b2017-06-21 23:46:41 +00001152 if (!WS.getSize())
1153 report_fatal_error("data symbols must have a size set with .size: " +
1154 WS.getName());
Sam Cleggc38e9472017-06-02 01:05:24 +00001155
Sam Cleggfe6414b2017-06-21 23:46:41 +00001156 int64_t Size = 0;
1157 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
1158 report_fatal_error(".size expression must be evaluatable");
Dan Gohmand934cb82017-02-24 23:18:00 +00001159
Sam Clegg759631c2017-09-15 20:54:59 +00001160 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
Sam Cleggea7cace2018-01-09 23:43:14 +00001161 assert(DataSection.isWasmData());
Sam Clegg7c395942017-09-14 23:07:53 +00001162
Sam Clegg6c899ba2018-02-23 05:08:34 +00001163 // For each data symbol, export it in the symtab as a reference to the
1164 // corresponding Wasm data segment.
1165 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1166 DataSection.getSegmentIndex(),
1167 static_cast<uint32_t>(Layout.getSymbolOffset(WS)),
1168 static_cast<uint32_t>(Size)};
1169 DataLocations[&WS] = Ref;
1170 DEBUG(dbgs() << " -> segment index: " << Ref.Segment);
1171 } else {
1172 // A "true" Wasm global (currently just __stack_pointer)
Eric Christopher545932b2018-02-23 21:14:47 +00001173 if (WS.isDefined())
Sam Clegg6c899ba2018-02-23 05:08:34 +00001174 report_fatal_error("don't yet support defined globals");
Sam Clegg6c899ba2018-02-23 05:08:34 +00001175
Eric Christopher545932b2018-02-23 21:14:47 +00001176 // An import; the index was assigned above
1177 DEBUG(dbgs() << " -> global index: " << WasmIndices.find(&WS)->second
1178 << "\n");
Dan Gohmand934cb82017-02-24 23:18:00 +00001179 }
1180 }
1181
Nicholas Wilson586320c2018-02-28 17:19:48 +00001182 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1183 // process these in a separate pass because we need to have processed the
1184 // target of the alias before the alias itself and the symbols are not
1185 // necessarily ordered in this way.
Sam Cleggb7787fd2017-06-20 04:04:59 +00001186 for (const MCSymbol &S : Asm.symbols()) {
1187 if (!S.isVariable())
1188 continue;
Sam Clegg31a2c802017-09-20 21:17:04 +00001189
Sam Cleggcd65f692018-01-11 23:59:16 +00001190 assert(S.isDefined());
Sam Cleggb7787fd2017-06-20 04:04:59 +00001191
Sam Clegg5e3d33a2017-07-07 02:01:29 +00001192 // Find the target symbol of this weak alias and export that index
Sam Cleggaff1c4d2017-09-15 19:22:01 +00001193 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1194 const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS);
Sam Clegg5e3d33a2017-07-07 02:01:29 +00001195 DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n");
Sam Cleggb7787fd2017-06-20 04:04:59 +00001196
Sam Clegg6c899ba2018-02-23 05:08:34 +00001197 if (WS.isFunction()) {
1198 assert(WasmIndices.count(ResolvedSym) > 0);
1199 uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
1200 WasmIndices[&WS] = WasmIndex;
1201 DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
1202 } else if (WS.isData()) {
1203 assert(DataLocations.count(ResolvedSym) > 0);
1204 const wasm::WasmDataReference &Ref =
1205 DataLocations.find(ResolvedSym)->second;
1206 DataLocations[&WS] = Ref;
1207 DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
1208 } else {
1209 report_fatal_error("don't yet support global aliases");
1210 }
Nicholas Wilson586320c2018-02-28 17:19:48 +00001211 }
Sam Clegg31a2c802017-09-20 21:17:04 +00001212
Nicholas Wilson586320c2018-02-28 17:19:48 +00001213 // Finally, populate the symbol table itself, in its "natural" order.
1214 for (const MCSymbol &S : Asm.symbols()) {
1215 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1216 if (WS.isTemporary() && WS.getName().empty())
1217 continue;
1218 if (WS.isComdat() && !WS.isDefined())
1219 continue;
1220 if (WS.isTemporary() && WS.isData() && !WS.getSize())
1221 continue;
1222
1223 uint32_t Flags = 0;
1224 if (WS.isWeak())
1225 Flags |= wasm::WASM_SYMBOL_BINDING_WEAK;
1226 if (WS.isHidden())
1227 Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
1228 if (!WS.isExternal() && WS.isDefined())
1229 Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
1230 if (WS.isUndefined())
1231 Flags |= wasm::WASM_SYMBOL_UNDEFINED;
1232
1233 wasm::WasmSymbolInfo Info;
1234 Info.Name = WS.getName();
1235 Info.Kind = WS.getType();
1236 Info.Flags = Flags;
1237 if (!WS.isData())
1238 Info.ElementIndex = WasmIndices.find(&WS)->second;
1239 else if (WS.isDefined())
1240 Info.DataRef = DataLocations.find(&WS)->second;
1241 SymbolIndices[&WS] = SymbolInfos.size();
1242 SymbolInfos.emplace_back(Info);
Sam Cleggb7787fd2017-06-20 04:04:59 +00001243 }
1244
Sam Clegg6006e092017-12-22 20:31:39 +00001245 {
1246 auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
Sam Cleggf9edbe92018-01-31 19:28:47 +00001247 // Functions referenced by a relocation need to put in the table. This is
1248 // purely to make the object file's provisional values readable, and is
1249 // ignored by the linker, which re-calculates the relocations itself.
1250 if (Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 &&
1251 Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB)
1252 return;
1253 assert(Rel.Symbol->isFunction());
1254 const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol);
Sam Clegg6c899ba2018-02-23 05:08:34 +00001255 uint32_t FunctionIndex = WasmIndices.find(&WS)->second;
Sam Cleggf9edbe92018-01-31 19:28:47 +00001256 uint32_t TableIndex = TableElems.size() + kInitialTableOffset;
1257 if (TableIndices.try_emplace(&WS, TableIndex).second) {
1258 DEBUG(dbgs() << " -> adding " << WS.getName()
1259 << " to table: " << TableIndex << "\n");
Sam Clegg6c899ba2018-02-23 05:08:34 +00001260 TableElems.push_back(FunctionIndex);
Sam Cleggf9edbe92018-01-31 19:28:47 +00001261 registerFunctionType(WS);
Sam Clegg6006e092017-12-22 20:31:39 +00001262 }
1263 };
Dan Gohman970d02c2017-03-30 23:58:19 +00001264
Sam Clegg6006e092017-12-22 20:31:39 +00001265 for (const WasmRelocationEntry &RelEntry : CodeRelocations)
1266 HandleReloc(RelEntry);
1267 for (const WasmRelocationEntry &RelEntry : DataRelocations)
1268 HandleReloc(RelEntry);
Dan Gohmand934cb82017-02-24 23:18:00 +00001269 }
1270
Sam Cleggbafe6902017-12-15 00:17:10 +00001271 // Translate .init_array section contents into start functions.
1272 for (const MCSection &S : Asm) {
1273 const auto &WS = static_cast<const MCSectionWasm &>(S);
1274 if (WS.getSectionName().startswith(".fini_array"))
1275 report_fatal_error(".fini_array sections are unsupported");
1276 if (!WS.getSectionName().startswith(".init_array"))
1277 continue;
1278 if (WS.getFragmentList().empty())
1279 continue;
1280 if (WS.getFragmentList().size() != 2)
1281 report_fatal_error("only one .init_array section fragment supported");
1282 const MCFragment &AlignFrag = *WS.begin();
1283 if (AlignFrag.getKind() != MCFragment::FT_Align)
1284 report_fatal_error(".init_array section should be aligned");
1285 if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4))
1286 report_fatal_error(".init_array section should be aligned for pointers");
1287 const MCFragment &Frag = *std::next(WS.begin());
1288 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1289 report_fatal_error("only data supported in .init_array section");
1290 uint16_t Priority = UINT16_MAX;
1291 if (WS.getSectionName().size() != 11) {
1292 if (WS.getSectionName()[11] != '.')
1293 report_fatal_error(".init_array section priority should start with '.'");
1294 if (WS.getSectionName().substr(12).getAsInteger(10, Priority))
1295 report_fatal_error("invalid .init_array section priority");
1296 }
1297 const auto &DataFrag = cast<MCDataFragment>(Frag);
1298 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1299 for (const uint8_t *p = (const uint8_t *)Contents.data(),
1300 *end = (const uint8_t *)Contents.data() + Contents.size();
1301 p != end; ++p) {
1302 if (*p != 0)
1303 report_fatal_error("non-symbolic data in .init_array section");
1304 }
1305 for (const MCFixup &Fixup : DataFrag.getFixups()) {
1306 assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1307 const MCExpr *Expr = Fixup.getValue();
1308 auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr);
1309 if (!Sym)
1310 report_fatal_error("fixups in .init_array should be symbol references");
1311 if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION)
1312 report_fatal_error("symbols in .init_array should be for functions");
1313 auto I = SymbolIndices.find(cast<MCSymbolWasm>(&Sym->getSymbol()));
1314 if (I == SymbolIndices.end())
1315 report_fatal_error("symbols in .init_array should be defined");
1316 uint32_t Index = I->second;
1317 InitFuncs.push_back(std::make_pair(Priority, Index));
1318 }
1319 }
1320
Dan Gohman18eafb62017-02-22 01:23:18 +00001321 // Write out the Wasm header.
1322 writeHeader(Asm);
1323
Sam Clegg9e15f352017-06-03 02:01:24 +00001324 writeTypeSection(FunctionTypes);
Sam Cleggf950b242017-12-11 23:03:38 +00001325 writeImportSection(Imports, DataSize, TableElems.size());
Sam Clegg9e15f352017-06-03 02:01:24 +00001326 writeFunctionSection(Functions);
Sam Cleggf950b242017-12-11 23:03:38 +00001327 // Skip the "table" section; we import the table instead.
1328 // Skip the "memory" section; we import the memory instead.
Sam Clegg7c395942017-09-14 23:07:53 +00001329 writeGlobalSection();
Sam Clegg9e15f352017-06-03 02:01:24 +00001330 writeExportSection(Exports);
Sam Clegg9e15f352017-06-03 02:01:24 +00001331 writeElemSection(TableElems);
Sam Cleggacd7d2b2017-06-06 19:15:05 +00001332 writeCodeSection(Asm, Layout, Functions);
Sam Clegg6c899ba2018-02-23 05:08:34 +00001333 writeDataSection();
Sam Cleggcfd44a22018-04-05 17:01:39 +00001334 writeUserCustomSections(CustomSections);
Nicholas Wilsonc22bfb62018-03-05 12:59:03 +00001335 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
Sam Clegg6f08c842018-04-24 18:11:36 +00001336 writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
1337 writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
Dan Gohman970d02c2017-03-30 23:58:19 +00001338
Dan Gohmand934cb82017-02-24 23:18:00 +00001339 // TODO: Translate the .comment section to the output.
Dan Gohmand934cb82017-02-24 23:18:00 +00001340 // TODO: Translate debug sections to the output.
Dan Gohman18eafb62017-02-22 01:23:18 +00001341}
1342
Lang Hames60fbc7c2017-10-10 16:28:07 +00001343std::unique_ptr<MCObjectWriter>
Lang Hames1301a872017-10-10 01:15:10 +00001344llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1345 raw_pwrite_stream &OS) {
Dan Gohman0917c9e2018-01-15 17:06:23 +00001346 return llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
Dan Gohman18eafb62017-02-22 01:23:18 +00001347}