Mercurial > hg > CbC > CbC_llvm
comparison lib/MC/WasmObjectWriter.cpp @ 121:803732b1fca8
LLVM 5.0
author | kono |
---|---|
date | Fri, 27 Oct 2017 17:07:41 +0900 |
parents | |
children | 3a76565eade5 |
comparison
equal
deleted
inserted
replaced
120:1172e4bd9c6f | 121:803732b1fca8 |
---|---|
1 //===- 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" | |
16 #include "llvm/BinaryFormat/Wasm.h" | |
17 #include "llvm/MC/MCAsmBackend.h" | |
18 #include "llvm/MC/MCAsmInfo.h" | |
19 #include "llvm/MC/MCAsmLayout.h" | |
20 #include "llvm/MC/MCAssembler.h" | |
21 #include "llvm/MC/MCContext.h" | |
22 #include "llvm/MC/MCExpr.h" | |
23 #include "llvm/MC/MCFixupKindInfo.h" | |
24 #include "llvm/MC/MCObjectFileInfo.h" | |
25 #include "llvm/MC/MCObjectWriter.h" | |
26 #include "llvm/MC/MCSectionWasm.h" | |
27 #include "llvm/MC/MCSymbolWasm.h" | |
28 #include "llvm/MC/MCValue.h" | |
29 #include "llvm/MC/MCWasmObjectWriter.h" | |
30 #include "llvm/Support/Casting.h" | |
31 #include "llvm/Support/Debug.h" | |
32 #include "llvm/Support/ErrorHandling.h" | |
33 #include "llvm/Support/LEB128.h" | |
34 #include "llvm/Support/StringSaver.h" | |
35 #include <vector> | |
36 | |
37 using namespace llvm; | |
38 | |
39 #define DEBUG_TYPE "mc" | |
40 | |
41 namespace { | |
42 | |
43 // For patching purposes, we need to remember where each section starts, both | |
44 // for patching up the section size field, and for patching up references to | |
45 // locations within the section. | |
46 struct SectionBookkeeping { | |
47 // Where the size of the section is written. | |
48 uint64_t SizeOffset; | |
49 // Where the contents of the section starts (after the header). | |
50 uint64_t ContentsOffset; | |
51 }; | |
52 | |
53 // The signature of a wasm function, in a struct capable of being used as a | |
54 // DenseMap key. | |
55 struct WasmFunctionType { | |
56 // Support empty and tombstone instances, needed by DenseMap. | |
57 enum { Plain, Empty, Tombstone } State; | |
58 | |
59 // The return types of the function. | |
60 SmallVector<wasm::ValType, 1> Returns; | |
61 | |
62 // The parameter types of the function. | |
63 SmallVector<wasm::ValType, 4> Params; | |
64 | |
65 WasmFunctionType() : State(Plain) {} | |
66 | |
67 bool operator==(const WasmFunctionType &Other) const { | |
68 return State == Other.State && Returns == Other.Returns && | |
69 Params == Other.Params; | |
70 } | |
71 }; | |
72 | |
73 // Traits for using WasmFunctionType in a DenseMap. | |
74 struct WasmFunctionTypeDenseMapInfo { | |
75 static WasmFunctionType getEmptyKey() { | |
76 WasmFunctionType FuncTy; | |
77 FuncTy.State = WasmFunctionType::Empty; | |
78 return FuncTy; | |
79 } | |
80 static WasmFunctionType getTombstoneKey() { | |
81 WasmFunctionType FuncTy; | |
82 FuncTy.State = WasmFunctionType::Tombstone; | |
83 return FuncTy; | |
84 } | |
85 static unsigned getHashValue(const WasmFunctionType &FuncTy) { | |
86 uintptr_t Value = FuncTy.State; | |
87 for (wasm::ValType Ret : FuncTy.Returns) | |
88 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret)); | |
89 for (wasm::ValType Param : FuncTy.Params) | |
90 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param)); | |
91 return Value; | |
92 } | |
93 static bool isEqual(const WasmFunctionType &LHS, | |
94 const WasmFunctionType &RHS) { | |
95 return LHS == RHS; | |
96 } | |
97 }; | |
98 | |
99 // A wasm data segment. A wasm binary contains only a single data section | |
100 // but that can contain many segments, each with their own virtual location | |
101 // in memory. Each MCSection data created by llvm is modeled as its own | |
102 // wasm data segment. | |
103 struct WasmDataSegment { | |
104 MCSectionWasm *Section; | |
105 StringRef Name; | |
106 uint32_t Offset; | |
107 uint32_t Alignment; | |
108 uint32_t Flags; | |
109 SmallVector<char, 4> Data; | |
110 }; | |
111 | |
112 // A wasm import to be written into the import section. | |
113 struct WasmImport { | |
114 StringRef ModuleName; | |
115 StringRef FieldName; | |
116 unsigned Kind; | |
117 int32_t Type; | |
118 }; | |
119 | |
120 // A wasm function to be written into the function section. | |
121 struct WasmFunction { | |
122 int32_t Type; | |
123 const MCSymbolWasm *Sym; | |
124 }; | |
125 | |
126 // A wasm export to be written into the export section. | |
127 struct WasmExport { | |
128 StringRef FieldName; | |
129 unsigned Kind; | |
130 uint32_t Index; | |
131 }; | |
132 | |
133 // A wasm global to be written into the global section. | |
134 struct WasmGlobal { | |
135 wasm::ValType Type; | |
136 bool IsMutable; | |
137 bool HasImport; | |
138 uint64_t InitialValue; | |
139 uint32_t ImportIndex; | |
140 }; | |
141 | |
142 // Information about a single relocation. | |
143 struct WasmRelocationEntry { | |
144 uint64_t Offset; // Where is the relocation. | |
145 const MCSymbolWasm *Symbol; // The symbol to relocate with. | |
146 int64_t Addend; // A value to add to the symbol. | |
147 unsigned Type; // The type of the relocation. | |
148 const MCSectionWasm *FixupSection;// The section the relocation is targeting. | |
149 | |
150 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, | |
151 int64_t Addend, unsigned Type, | |
152 const MCSectionWasm *FixupSection) | |
153 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), | |
154 FixupSection(FixupSection) {} | |
155 | |
156 bool hasAddend() const { | |
157 switch (Type) { | |
158 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
159 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
160 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
161 return true; | |
162 default: | |
163 return false; | |
164 } | |
165 } | |
166 | |
167 void print(raw_ostream &Out) const { | |
168 Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend | |
169 << ", Type=" << Type | |
170 << ", FixupSection=" << FixupSection->getSectionName(); | |
171 } | |
172 | |
173 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | |
174 LLVM_DUMP_METHOD void dump() const { print(dbgs()); } | |
175 #endif | |
176 }; | |
177 | |
178 #if !defined(NDEBUG) | |
179 raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { | |
180 Rel.print(OS); | |
181 return OS; | |
182 } | |
183 #endif | |
184 | |
185 class WasmObjectWriter : public MCObjectWriter { | |
186 /// Helper struct for containing some precomputed information on symbols. | |
187 struct WasmSymbolData { | |
188 const MCSymbolWasm *Symbol; | |
189 StringRef Name; | |
190 | |
191 // Support lexicographic sorting. | |
192 bool operator<(const WasmSymbolData &RHS) const { return Name < RHS.Name; } | |
193 }; | |
194 | |
195 /// The target specific Wasm writer instance. | |
196 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter; | |
197 | |
198 // Relocations for fixing up references in the code section. | |
199 std::vector<WasmRelocationEntry> CodeRelocations; | |
200 | |
201 // Relocations for fixing up references in the data section. | |
202 std::vector<WasmRelocationEntry> DataRelocations; | |
203 | |
204 // Index values to use for fixing up call_indirect type indices. | |
205 // Maps function symbols to the index of the type of the function | |
206 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices; | |
207 // Maps function symbols to the table element index space. Used | |
208 // for TABLE_INDEX relocation types (i.e. address taken functions). | |
209 DenseMap<const MCSymbolWasm *, uint32_t> IndirectSymbolIndices; | |
210 // Maps function/global symbols to the function/global index space. | |
211 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices; | |
212 | |
213 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> | |
214 FunctionTypeIndices; | |
215 SmallVector<WasmFunctionType, 4> FunctionTypes; | |
216 SmallVector<WasmGlobal, 4> Globals; | |
217 unsigned NumGlobalImports = 0; | |
218 | |
219 // TargetObjectWriter wrappers. | |
220 bool is64Bit() const { return TargetObjectWriter->is64Bit(); } | |
221 unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const { | |
222 return TargetObjectWriter->getRelocType(Target, Fixup); | |
223 } | |
224 | |
225 void startSection(SectionBookkeeping &Section, unsigned SectionId, | |
226 const char *Name = nullptr); | |
227 void endSection(SectionBookkeeping &Section); | |
228 | |
229 public: | |
230 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, | |
231 raw_pwrite_stream &OS) | |
232 : MCObjectWriter(OS, /*IsLittleEndian=*/true), | |
233 TargetObjectWriter(std::move(MOTW)) {} | |
234 | |
235 private: | |
236 ~WasmObjectWriter() override; | |
237 | |
238 void reset() override { | |
239 CodeRelocations.clear(); | |
240 DataRelocations.clear(); | |
241 TypeIndices.clear(); | |
242 SymbolIndices.clear(); | |
243 IndirectSymbolIndices.clear(); | |
244 FunctionTypeIndices.clear(); | |
245 FunctionTypes.clear(); | |
246 Globals.clear(); | |
247 MCObjectWriter::reset(); | |
248 NumGlobalImports = 0; | |
249 } | |
250 | |
251 void writeHeader(const MCAssembler &Asm); | |
252 | |
253 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, | |
254 const MCFragment *Fragment, const MCFixup &Fixup, | |
255 MCValue Target, uint64_t &FixedValue) override; | |
256 | |
257 void executePostLayoutBinding(MCAssembler &Asm, | |
258 const MCAsmLayout &Layout) override; | |
259 | |
260 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; | |
261 | |
262 void writeString(const StringRef Str) { | |
263 encodeULEB128(Str.size(), getStream()); | |
264 writeBytes(Str); | |
265 } | |
266 | |
267 void writeValueType(wasm::ValType Ty) { | |
268 encodeSLEB128(int32_t(Ty), getStream()); | |
269 } | |
270 | |
271 void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes); | |
272 void writeImportSection(ArrayRef<WasmImport> Imports); | |
273 void writeFunctionSection(ArrayRef<WasmFunction> Functions); | |
274 void writeTableSection(uint32_t NumElements); | |
275 void writeMemorySection(uint32_t DataSize); | |
276 void writeGlobalSection(); | |
277 void writeExportSection(ArrayRef<WasmExport> Exports); | |
278 void writeElemSection(ArrayRef<uint32_t> TableElems); | |
279 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, | |
280 ArrayRef<WasmFunction> Functions); | |
281 void writeDataSection(ArrayRef<WasmDataSegment> Segments); | |
282 void writeNameSection(ArrayRef<WasmFunction> Functions, | |
283 ArrayRef<WasmImport> Imports, | |
284 uint32_t NumFuncImports); | |
285 void writeCodeRelocSection(); | |
286 void writeDataRelocSection(); | |
287 void writeLinkingMetaDataSection( | |
288 ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, | |
289 SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags, | |
290 bool HasStackPointer, uint32_t StackPointerGlobal); | |
291 | |
292 uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); | |
293 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, | |
294 uint64_t ContentsOffset); | |
295 | |
296 void writeRelocations(ArrayRef<WasmRelocationEntry> Relocations); | |
297 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); | |
298 uint32_t getFunctionType(const MCSymbolWasm& Symbol); | |
299 uint32_t registerFunctionType(const MCSymbolWasm& Symbol); | |
300 }; | |
301 | |
302 } // end anonymous namespace | |
303 | |
304 WasmObjectWriter::~WasmObjectWriter() {} | |
305 | |
306 // Write out a section header and a patchable section size field. | |
307 void WasmObjectWriter::startSection(SectionBookkeeping &Section, | |
308 unsigned SectionId, | |
309 const char *Name) { | |
310 assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && | |
311 "Only custom sections can have names"); | |
312 | |
313 DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); | |
314 encodeULEB128(SectionId, getStream()); | |
315 | |
316 Section.SizeOffset = getStream().tell(); | |
317 | |
318 // The section size. We don't know the size yet, so reserve enough space | |
319 // for any 32-bit value; we'll patch it later. | |
320 encodeULEB128(UINT32_MAX, getStream()); | |
321 | |
322 // The position where the section starts, for measuring its size. | |
323 Section.ContentsOffset = getStream().tell(); | |
324 | |
325 // Custom sections in wasm also have a string identifier. | |
326 if (SectionId == wasm::WASM_SEC_CUSTOM) { | |
327 assert(Name); | |
328 writeString(StringRef(Name)); | |
329 } | |
330 } | |
331 | |
332 // Now that the section is complete and we know how big it is, patch up the | |
333 // section size field at the start of the section. | |
334 void WasmObjectWriter::endSection(SectionBookkeeping &Section) { | |
335 uint64_t Size = getStream().tell() - Section.ContentsOffset; | |
336 if (uint32_t(Size) != Size) | |
337 report_fatal_error("section size does not fit in a uint32_t"); | |
338 | |
339 DEBUG(dbgs() << "endSection size=" << Size << "\n"); | |
340 | |
341 // Write the final section size to the payload_len field, which follows | |
342 // the section id byte. | |
343 uint8_t Buffer[16]; | |
344 unsigned SizeLen = encodeULEB128(Size, Buffer, 5); | |
345 assert(SizeLen == 5); | |
346 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset); | |
347 } | |
348 | |
349 // Emit the Wasm header. | |
350 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) { | |
351 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic))); | |
352 writeLE32(wasm::WasmVersion); | |
353 } | |
354 | |
355 void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, | |
356 const MCAsmLayout &Layout) { | |
357 } | |
358 | |
359 void WasmObjectWriter::recordRelocation(MCAssembler &Asm, | |
360 const MCAsmLayout &Layout, | |
361 const MCFragment *Fragment, | |
362 const MCFixup &Fixup, MCValue Target, | |
363 uint64_t &FixedValue) { | |
364 MCAsmBackend &Backend = Asm.getBackend(); | |
365 bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & | |
366 MCFixupKindInfo::FKF_IsPCRel; | |
367 const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent()); | |
368 uint64_t C = Target.getConstant(); | |
369 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); | |
370 MCContext &Ctx = Asm.getContext(); | |
371 | |
372 if (const MCSymbolRefExpr *RefB = Target.getSymB()) { | |
373 assert(RefB->getKind() == MCSymbolRefExpr::VK_None && | |
374 "Should not have constructed this"); | |
375 | |
376 // Let A, B and C being the components of Target and R be the location of | |
377 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). | |
378 // If it is pcrel, we want to compute (A - B + C - R). | |
379 | |
380 // In general, Wasm has no relocations for -B. It can only represent (A + C) | |
381 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can | |
382 // replace B to implement it: (A - R - K + C) | |
383 if (IsPCRel) { | |
384 Ctx.reportError( | |
385 Fixup.getLoc(), | |
386 "No relocation available to represent this relative expression"); | |
387 return; | |
388 } | |
389 | |
390 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol()); | |
391 | |
392 if (SymB.isUndefined()) { | |
393 Ctx.reportError(Fixup.getLoc(), | |
394 Twine("symbol '") + SymB.getName() + | |
395 "' can not be undefined in a subtraction expression"); | |
396 return; | |
397 } | |
398 | |
399 assert(!SymB.isAbsolute() && "Should have been folded"); | |
400 const MCSection &SecB = SymB.getSection(); | |
401 if (&SecB != &FixupSection) { | |
402 Ctx.reportError(Fixup.getLoc(), | |
403 "Cannot represent a difference across sections"); | |
404 return; | |
405 } | |
406 | |
407 uint64_t SymBOffset = Layout.getSymbolOffset(SymB); | |
408 uint64_t K = SymBOffset - FixupOffset; | |
409 IsPCRel = true; | |
410 C -= K; | |
411 } | |
412 | |
413 // We either rejected the fixup or folded B into C at this point. | |
414 const MCSymbolRefExpr *RefA = Target.getSymA(); | |
415 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr; | |
416 | |
417 if (SymA && SymA->isVariable()) { | |
418 const MCExpr *Expr = SymA->getVariableValue(); | |
419 const auto *Inner = cast<MCSymbolRefExpr>(Expr); | |
420 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) | |
421 llvm_unreachable("weakref used in reloc not yet implemented"); | |
422 } | |
423 | |
424 // Put any constant offset in an addend. Offsets can be negative, and | |
425 // LLVM expects wrapping, in contrast to wasm's immediates which can't | |
426 // be negative and don't wrap. | |
427 FixedValue = 0; | |
428 | |
429 if (SymA) | |
430 SymA->setUsedInReloc(); | |
431 | |
432 assert(!IsPCRel); | |
433 assert(SymA); | |
434 | |
435 unsigned Type = getRelocType(Target, Fixup); | |
436 | |
437 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); | |
438 DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); | |
439 | |
440 if (FixupSection.isWasmData()) | |
441 DataRelocations.push_back(Rec); | |
442 else if (FixupSection.getKind().isText()) | |
443 CodeRelocations.push_back(Rec); | |
444 else if (!FixupSection.getKind().isMetadata()) | |
445 // TODO(sbc): Add support for debug sections. | |
446 llvm_unreachable("unexpected section type"); | |
447 } | |
448 | |
449 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded | |
450 // to allow patching. | |
451 static void | |
452 WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { | |
453 uint8_t Buffer[5]; | |
454 unsigned SizeLen = encodeULEB128(X, Buffer, 5); | |
455 assert(SizeLen == 5); | |
456 Stream.pwrite((char *)Buffer, SizeLen, Offset); | |
457 } | |
458 | |
459 // Write X as an signed LEB value at offset Offset in Stream, padded | |
460 // to allow patching. | |
461 static void | |
462 WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) { | |
463 uint8_t Buffer[5]; | |
464 unsigned SizeLen = encodeSLEB128(X, Buffer, 5); | |
465 assert(SizeLen == 5); | |
466 Stream.pwrite((char *)Buffer, SizeLen, Offset); | |
467 } | |
468 | |
469 // Write X as a plain integer value at offset Offset in Stream. | |
470 static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { | |
471 uint8_t Buffer[4]; | |
472 support::endian::write32le(Buffer, X); | |
473 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); | |
474 } | |
475 | |
476 static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) { | |
477 if (Symbol.isVariable()) { | |
478 const MCExpr *Expr = Symbol.getVariableValue(); | |
479 auto *Inner = cast<MCSymbolRefExpr>(Expr); | |
480 return cast<MCSymbolWasm>(&Inner->getSymbol()); | |
481 } | |
482 return &Symbol; | |
483 } | |
484 | |
485 // Compute a value to write into the code at the location covered | |
486 // by RelEntry. This value isn't used by the static linker, since | |
487 // we have addends; it just serves to make the code more readable | |
488 // and to make standalone wasm modules directly usable. | |
489 uint32_t | |
490 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { | |
491 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); | |
492 | |
493 // For undefined symbols, use a hopefully invalid value. | |
494 if (!Sym->isDefined(/*SetUsed=*/false)) | |
495 return UINT32_MAX; | |
496 | |
497 uint32_t GlobalIndex = SymbolIndices[Sym]; | |
498 const WasmGlobal& Global = Globals[GlobalIndex - NumGlobalImports]; | |
499 uint64_t Address = Global.InitialValue + RelEntry.Addend; | |
500 | |
501 // Ignore overflow. LLVM allows address arithmetic to silently wrap. | |
502 uint32_t Value = Address; | |
503 | |
504 return Value; | |
505 } | |
506 | |
507 static void addData(SmallVectorImpl<char> &DataBytes, | |
508 MCSectionWasm &DataSection) { | |
509 DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); | |
510 | |
511 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); | |
512 | |
513 size_t LastFragmentSize = 0; | |
514 for (const MCFragment &Frag : DataSection) { | |
515 if (Frag.hasInstructions()) | |
516 report_fatal_error("only data supported in data sections"); | |
517 | |
518 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) { | |
519 if (Align->getValueSize() != 1) | |
520 report_fatal_error("only byte values supported for alignment"); | |
521 // If nops are requested, use zeros, as this is the data section. | |
522 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); | |
523 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(), | |
524 Align->getAlignment()), | |
525 DataBytes.size() + | |
526 Align->getMaxBytesToEmit()); | |
527 DataBytes.resize(Size, Value); | |
528 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) { | |
529 DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue()); | |
530 } else { | |
531 const auto &DataFrag = cast<MCDataFragment>(Frag); | |
532 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); | |
533 | |
534 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); | |
535 LastFragmentSize = Contents.size(); | |
536 } | |
537 } | |
538 | |
539 // Don't allow empty segments, or segments that end with zero-sized | |
540 // fragment, otherwise the linker cannot map symbols to a unique | |
541 // data segment. This can be triggered by zero-sized structs | |
542 // See: test/MC/WebAssembly/bss.ll | |
543 if (LastFragmentSize == 0) | |
544 DataBytes.resize(DataBytes.size() + 1); | |
545 DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); | |
546 } | |
547 | |
548 uint32_t WasmObjectWriter::getRelocationIndexValue( | |
549 const WasmRelocationEntry &RelEntry) { | |
550 switch (RelEntry.Type) { | |
551 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
552 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: | |
553 if (!IndirectSymbolIndices.count(RelEntry.Symbol)) | |
554 report_fatal_error("symbol not found table index space: " + | |
555 RelEntry.Symbol->getName()); | |
556 return IndirectSymbolIndices[RelEntry.Symbol]; | |
557 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
558 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: | |
559 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: | |
560 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
561 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
562 if (!SymbolIndices.count(RelEntry.Symbol)) | |
563 report_fatal_error("symbol not found function/global index space: " + | |
564 RelEntry.Symbol->getName()); | |
565 return SymbolIndices[RelEntry.Symbol]; | |
566 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
567 if (!TypeIndices.count(RelEntry.Symbol)) | |
568 report_fatal_error("symbol not found in type index space: " + | |
569 RelEntry.Symbol->getName()); | |
570 return TypeIndices[RelEntry.Symbol]; | |
571 default: | |
572 llvm_unreachable("invalid relocation type"); | |
573 } | |
574 } | |
575 | |
576 // Apply the portions of the relocation records that we can handle ourselves | |
577 // directly. | |
578 void WasmObjectWriter::applyRelocations( | |
579 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) { | |
580 raw_pwrite_stream &Stream = getStream(); | |
581 for (const WasmRelocationEntry &RelEntry : Relocations) { | |
582 uint64_t Offset = ContentsOffset + | |
583 RelEntry.FixupSection->getSectionOffset() + | |
584 RelEntry.Offset; | |
585 | |
586 DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); | |
587 switch (RelEntry.Type) { | |
588 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
589 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: | |
590 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: | |
591 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { | |
592 uint32_t Index = getRelocationIndexValue(RelEntry); | |
593 WritePatchableSLEB(Stream, Index, Offset); | |
594 break; | |
595 } | |
596 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { | |
597 uint32_t Index = getRelocationIndexValue(RelEntry); | |
598 WriteI32(Stream, Index, Offset); | |
599 break; | |
600 } | |
601 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { | |
602 uint32_t Value = getProvisionalValue(RelEntry); | |
603 WritePatchableSLEB(Stream, Value, Offset); | |
604 break; | |
605 } | |
606 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: { | |
607 uint32_t Value = getProvisionalValue(RelEntry); | |
608 WritePatchableLEB(Stream, Value, Offset); | |
609 break; | |
610 } | |
611 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: { | |
612 uint32_t Value = getProvisionalValue(RelEntry); | |
613 WriteI32(Stream, Value, Offset); | |
614 break; | |
615 } | |
616 default: | |
617 llvm_unreachable("invalid relocation type"); | |
618 } | |
619 } | |
620 } | |
621 | |
622 // Write out the portions of the relocation records that the linker will | |
623 // need to handle. | |
624 void WasmObjectWriter::writeRelocations( | |
625 ArrayRef<WasmRelocationEntry> Relocations) { | |
626 raw_pwrite_stream &Stream = getStream(); | |
627 for (const WasmRelocationEntry& RelEntry : Relocations) { | |
628 | |
629 uint64_t Offset = RelEntry.Offset + | |
630 RelEntry.FixupSection->getSectionOffset(); | |
631 uint32_t Index = getRelocationIndexValue(RelEntry); | |
632 | |
633 encodeULEB128(RelEntry.Type, Stream); | |
634 encodeULEB128(Offset, Stream); | |
635 encodeULEB128(Index, Stream); | |
636 if (RelEntry.hasAddend()) | |
637 encodeSLEB128(RelEntry.Addend, Stream); | |
638 } | |
639 } | |
640 | |
641 void WasmObjectWriter::writeTypeSection( | |
642 ArrayRef<WasmFunctionType> FunctionTypes) { | |
643 if (FunctionTypes.empty()) | |
644 return; | |
645 | |
646 SectionBookkeeping Section; | |
647 startSection(Section, wasm::WASM_SEC_TYPE); | |
648 | |
649 encodeULEB128(FunctionTypes.size(), getStream()); | |
650 | |
651 for (const WasmFunctionType &FuncTy : FunctionTypes) { | |
652 encodeSLEB128(wasm::WASM_TYPE_FUNC, getStream()); | |
653 encodeULEB128(FuncTy.Params.size(), getStream()); | |
654 for (wasm::ValType Ty : FuncTy.Params) | |
655 writeValueType(Ty); | |
656 encodeULEB128(FuncTy.Returns.size(), getStream()); | |
657 for (wasm::ValType Ty : FuncTy.Returns) | |
658 writeValueType(Ty); | |
659 } | |
660 | |
661 endSection(Section); | |
662 } | |
663 | |
664 void WasmObjectWriter::writeImportSection(ArrayRef<WasmImport> Imports) { | |
665 if (Imports.empty()) | |
666 return; | |
667 | |
668 SectionBookkeeping Section; | |
669 startSection(Section, wasm::WASM_SEC_IMPORT); | |
670 | |
671 encodeULEB128(Imports.size(), getStream()); | |
672 for (const WasmImport &Import : Imports) { | |
673 writeString(Import.ModuleName); | |
674 writeString(Import.FieldName); | |
675 | |
676 encodeULEB128(Import.Kind, getStream()); | |
677 | |
678 switch (Import.Kind) { | |
679 case wasm::WASM_EXTERNAL_FUNCTION: | |
680 encodeULEB128(Import.Type, getStream()); | |
681 break; | |
682 case wasm::WASM_EXTERNAL_GLOBAL: | |
683 encodeSLEB128(int32_t(Import.Type), getStream()); | |
684 encodeULEB128(0, getStream()); // mutability | |
685 break; | |
686 default: | |
687 llvm_unreachable("unsupported import kind"); | |
688 } | |
689 } | |
690 | |
691 endSection(Section); | |
692 } | |
693 | |
694 void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { | |
695 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 | |
708 void WasmObjectWriter::writeTableSection(uint32_t NumElements) { | |
709 // For now, always emit the table section, since indirect calls are not | |
710 // valid without it. In the future, we could perhaps be more clever and omit | |
711 // it if there are no indirect calls. | |
712 | |
713 SectionBookkeeping Section; | |
714 startSection(Section, wasm::WASM_SEC_TABLE); | |
715 | |
716 encodeULEB128(1, getStream()); // The number of tables. | |
717 // Fixed to 1 for now. | |
718 encodeSLEB128(wasm::WASM_TYPE_ANYFUNC, getStream()); // Type of table | |
719 encodeULEB128(0, getStream()); // flags | |
720 encodeULEB128(NumElements, getStream()); // initial | |
721 | |
722 endSection(Section); | |
723 } | |
724 | |
725 void WasmObjectWriter::writeMemorySection(uint32_t DataSize) { | |
726 // For now, always emit the memory section, since loads and stores are not | |
727 // valid without it. In the future, we could perhaps be more clever and omit | |
728 // it if there are no loads or stores. | |
729 SectionBookkeeping Section; | |
730 uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; | |
731 | |
732 startSection(Section, wasm::WASM_SEC_MEMORY); | |
733 encodeULEB128(1, getStream()); // number of memory spaces | |
734 | |
735 encodeULEB128(0, getStream()); // flags | |
736 encodeULEB128(NumPages, getStream()); // initial | |
737 | |
738 endSection(Section); | |
739 } | |
740 | |
741 void WasmObjectWriter::writeGlobalSection() { | |
742 if (Globals.empty()) | |
743 return; | |
744 | |
745 SectionBookkeeping Section; | |
746 startSection(Section, wasm::WASM_SEC_GLOBAL); | |
747 | |
748 encodeULEB128(Globals.size(), getStream()); | |
749 for (const WasmGlobal &Global : Globals) { | |
750 writeValueType(Global.Type); | |
751 write8(Global.IsMutable); | |
752 | |
753 if (Global.HasImport) { | |
754 assert(Global.InitialValue == 0); | |
755 write8(wasm::WASM_OPCODE_GET_GLOBAL); | |
756 encodeULEB128(Global.ImportIndex, getStream()); | |
757 } else { | |
758 assert(Global.ImportIndex == 0); | |
759 write8(wasm::WASM_OPCODE_I32_CONST); | |
760 encodeSLEB128(Global.InitialValue, getStream()); // offset | |
761 } | |
762 write8(wasm::WASM_OPCODE_END); | |
763 } | |
764 | |
765 endSection(Section); | |
766 } | |
767 | |
768 void WasmObjectWriter::writeExportSection(ArrayRef<WasmExport> Exports) { | |
769 if (Exports.empty()) | |
770 return; | |
771 | |
772 SectionBookkeeping Section; | |
773 startSection(Section, wasm::WASM_SEC_EXPORT); | |
774 | |
775 encodeULEB128(Exports.size(), getStream()); | |
776 for (const WasmExport &Export : Exports) { | |
777 writeString(Export.FieldName); | |
778 encodeSLEB128(Export.Kind, getStream()); | |
779 encodeULEB128(Export.Index, getStream()); | |
780 } | |
781 | |
782 endSection(Section); | |
783 } | |
784 | |
785 void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { | |
786 if (TableElems.empty()) | |
787 return; | |
788 | |
789 SectionBookkeeping Section; | |
790 startSection(Section, wasm::WASM_SEC_ELEM); | |
791 | |
792 encodeULEB128(1, getStream()); // number of "segments" | |
793 encodeULEB128(0, getStream()); // the table index | |
794 | |
795 // init expr for starting offset | |
796 write8(wasm::WASM_OPCODE_I32_CONST); | |
797 encodeSLEB128(0, getStream()); | |
798 write8(wasm::WASM_OPCODE_END); | |
799 | |
800 encodeULEB128(TableElems.size(), getStream()); | |
801 for (uint32_t Elem : TableElems) | |
802 encodeULEB128(Elem, getStream()); | |
803 | |
804 endSection(Section); | |
805 } | |
806 | |
807 void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, | |
808 const MCAsmLayout &Layout, | |
809 ArrayRef<WasmFunction> Functions) { | |
810 if (Functions.empty()) | |
811 return; | |
812 | |
813 SectionBookkeeping Section; | |
814 startSection(Section, wasm::WASM_SEC_CODE); | |
815 | |
816 encodeULEB128(Functions.size(), getStream()); | |
817 | |
818 for (const WasmFunction &Func : Functions) { | |
819 auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection()); | |
820 | |
821 int64_t Size = 0; | |
822 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) | |
823 report_fatal_error(".size expression must be evaluatable"); | |
824 | |
825 encodeULEB128(Size, getStream()); | |
826 FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); | |
827 Asm.writeSectionData(&FuncSection, Layout); | |
828 } | |
829 | |
830 // Apply fixups. | |
831 applyRelocations(CodeRelocations, Section.ContentsOffset); | |
832 | |
833 endSection(Section); | |
834 } | |
835 | |
836 void WasmObjectWriter::writeDataSection(ArrayRef<WasmDataSegment> Segments) { | |
837 if (Segments.empty()) | |
838 return; | |
839 | |
840 SectionBookkeeping Section; | |
841 startSection(Section, wasm::WASM_SEC_DATA); | |
842 | |
843 encodeULEB128(Segments.size(), getStream()); // count | |
844 | |
845 for (const WasmDataSegment & Segment : Segments) { | |
846 encodeULEB128(0, getStream()); // memory index | |
847 write8(wasm::WASM_OPCODE_I32_CONST); | |
848 encodeSLEB128(Segment.Offset, getStream()); // offset | |
849 write8(wasm::WASM_OPCODE_END); | |
850 encodeULEB128(Segment.Data.size(), getStream()); // size | |
851 Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset); | |
852 writeBytes(Segment.Data); // data | |
853 } | |
854 | |
855 // Apply fixups. | |
856 applyRelocations(DataRelocations, Section.ContentsOffset); | |
857 | |
858 endSection(Section); | |
859 } | |
860 | |
861 void WasmObjectWriter::writeNameSection( | |
862 ArrayRef<WasmFunction> Functions, | |
863 ArrayRef<WasmImport> Imports, | |
864 unsigned NumFuncImports) { | |
865 uint32_t TotalFunctions = NumFuncImports + Functions.size(); | |
866 if (TotalFunctions == 0) | |
867 return; | |
868 | |
869 SectionBookkeeping Section; | |
870 startSection(Section, wasm::WASM_SEC_CUSTOM, "name"); | |
871 SectionBookkeeping SubSection; | |
872 startSection(SubSection, wasm::WASM_NAMES_FUNCTION); | |
873 | |
874 encodeULEB128(TotalFunctions, getStream()); | |
875 uint32_t Index = 0; | |
876 for (const WasmImport &Import : Imports) { | |
877 if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { | |
878 encodeULEB128(Index, getStream()); | |
879 writeString(Import.FieldName); | |
880 ++Index; | |
881 } | |
882 } | |
883 for (const WasmFunction &Func : Functions) { | |
884 encodeULEB128(Index, getStream()); | |
885 writeString(Func.Sym->getName()); | |
886 ++Index; | |
887 } | |
888 | |
889 endSection(SubSection); | |
890 endSection(Section); | |
891 } | |
892 | |
893 void WasmObjectWriter::writeCodeRelocSection() { | |
894 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md | |
895 // for descriptions of the reloc sections. | |
896 | |
897 if (CodeRelocations.empty()) | |
898 return; | |
899 | |
900 SectionBookkeeping Section; | |
901 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); | |
902 | |
903 encodeULEB128(wasm::WASM_SEC_CODE, getStream()); | |
904 encodeULEB128(CodeRelocations.size(), getStream()); | |
905 | |
906 writeRelocations(CodeRelocations); | |
907 | |
908 endSection(Section); | |
909 } | |
910 | |
911 void WasmObjectWriter::writeDataRelocSection() { | |
912 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md | |
913 // for descriptions of the reloc sections. | |
914 | |
915 if (DataRelocations.empty()) | |
916 return; | |
917 | |
918 SectionBookkeeping Section; | |
919 startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); | |
920 | |
921 encodeULEB128(wasm::WASM_SEC_DATA, getStream()); | |
922 encodeULEB128(DataRelocations.size(), getStream()); | |
923 | |
924 writeRelocations(DataRelocations); | |
925 | |
926 endSection(Section); | |
927 } | |
928 | |
929 void WasmObjectWriter::writeLinkingMetaDataSection( | |
930 ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, | |
931 SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags, | |
932 bool HasStackPointer, uint32_t StackPointerGlobal) { | |
933 SectionBookkeeping Section; | |
934 startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); | |
935 SectionBookkeeping SubSection; | |
936 | |
937 if (HasStackPointer) { | |
938 startSection(SubSection, wasm::WASM_STACK_POINTER); | |
939 encodeULEB128(StackPointerGlobal, getStream()); // id | |
940 endSection(SubSection); | |
941 } | |
942 | |
943 if (SymbolFlags.size() != 0) { | |
944 startSection(SubSection, wasm::WASM_SYMBOL_INFO); | |
945 encodeULEB128(SymbolFlags.size(), getStream()); | |
946 for (auto Pair: SymbolFlags) { | |
947 writeString(Pair.first); | |
948 encodeULEB128(Pair.second, getStream()); | |
949 } | |
950 endSection(SubSection); | |
951 } | |
952 | |
953 if (DataSize > 0) { | |
954 startSection(SubSection, wasm::WASM_DATA_SIZE); | |
955 encodeULEB128(DataSize, getStream()); | |
956 endSection(SubSection); | |
957 } | |
958 | |
959 if (Segments.size()) { | |
960 startSection(SubSection, wasm::WASM_SEGMENT_INFO); | |
961 encodeULEB128(Segments.size(), getStream()); | |
962 for (const WasmDataSegment &Segment : Segments) { | |
963 writeString(Segment.Name); | |
964 encodeULEB128(Segment.Alignment, getStream()); | |
965 encodeULEB128(Segment.Flags, getStream()); | |
966 } | |
967 endSection(SubSection); | |
968 } | |
969 | |
970 endSection(Section); | |
971 } | |
972 | |
973 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { | |
974 assert(Symbol.isFunction()); | |
975 assert(TypeIndices.count(&Symbol)); | |
976 return TypeIndices[&Symbol]; | |
977 } | |
978 | |
979 uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) { | |
980 assert(Symbol.isFunction()); | |
981 | |
982 WasmFunctionType F; | |
983 const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol); | |
984 F.Returns = ResolvedSym->getReturns(); | |
985 F.Params = ResolvedSym->getParams(); | |
986 | |
987 auto Pair = | |
988 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size())); | |
989 if (Pair.second) | |
990 FunctionTypes.push_back(F); | |
991 TypeIndices[&Symbol] = Pair.first->second; | |
992 | |
993 DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n"); | |
994 DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n"); | |
995 return Pair.first->second; | |
996 } | |
997 | |
998 void WasmObjectWriter::writeObject(MCAssembler &Asm, | |
999 const MCAsmLayout &Layout) { | |
1000 DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); | |
1001 MCContext &Ctx = Asm.getContext(); | |
1002 wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; | |
1003 | |
1004 // Collect information from the available symbols. | |
1005 SmallVector<WasmFunction, 4> Functions; | |
1006 SmallVector<uint32_t, 4> TableElems; | |
1007 SmallVector<WasmImport, 4> Imports; | |
1008 SmallVector<WasmExport, 4> Exports; | |
1009 SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags; | |
1010 SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken; | |
1011 unsigned NumFuncImports = 0; | |
1012 SmallVector<WasmDataSegment, 4> DataSegments; | |
1013 uint32_t StackPointerGlobal = 0; | |
1014 uint32_t DataSize = 0; | |
1015 bool HasStackPointer = false; | |
1016 | |
1017 // Populate the IsAddressTaken set. | |
1018 for (const WasmRelocationEntry &RelEntry : CodeRelocations) { | |
1019 switch (RelEntry.Type) { | |
1020 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: | |
1021 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: | |
1022 IsAddressTaken.insert(RelEntry.Symbol); | |
1023 break; | |
1024 default: | |
1025 break; | |
1026 } | |
1027 } | |
1028 for (const WasmRelocationEntry &RelEntry : DataRelocations) { | |
1029 switch (RelEntry.Type) { | |
1030 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: | |
1031 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: | |
1032 IsAddressTaken.insert(RelEntry.Symbol); | |
1033 break; | |
1034 default: | |
1035 break; | |
1036 } | |
1037 } | |
1038 | |
1039 // Populate FunctionTypeIndices and Imports. | |
1040 for (const MCSymbol &S : Asm.symbols()) { | |
1041 const auto &WS = static_cast<const MCSymbolWasm &>(S); | |
1042 | |
1043 if (WS.isTemporary()) | |
1044 continue; | |
1045 | |
1046 if (WS.isFunction()) | |
1047 registerFunctionType(WS); | |
1048 | |
1049 // If the symbol is not defined in this translation unit, import it. | |
1050 if (!WS.isDefined(/*SetUsed=*/false)) { | |
1051 WasmImport Import; | |
1052 Import.ModuleName = WS.getModuleName(); | |
1053 Import.FieldName = WS.getName(); | |
1054 | |
1055 if (WS.isFunction()) { | |
1056 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; | |
1057 Import.Type = getFunctionType(WS); | |
1058 SymbolIndices[&WS] = NumFuncImports; | |
1059 ++NumFuncImports; | |
1060 } else { | |
1061 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; | |
1062 Import.Type = int32_t(PtrType); | |
1063 SymbolIndices[&WS] = NumGlobalImports; | |
1064 ++NumGlobalImports; | |
1065 } | |
1066 | |
1067 Imports.push_back(Import); | |
1068 } | |
1069 } | |
1070 | |
1071 // In the special .global_variables section, we've encoded global | |
1072 // variables used by the function. Translate them into the Globals | |
1073 // list. | |
1074 MCSectionWasm *GlobalVars = | |
1075 Ctx.getWasmSection(".global_variables", SectionKind::getMetadata()); | |
1076 if (!GlobalVars->getFragmentList().empty()) { | |
1077 if (GlobalVars->getFragmentList().size() != 1) | |
1078 report_fatal_error("only one .global_variables fragment supported"); | |
1079 const MCFragment &Frag = *GlobalVars->begin(); | |
1080 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) | |
1081 report_fatal_error("only data supported in .global_variables"); | |
1082 const auto &DataFrag = cast<MCDataFragment>(Frag); | |
1083 if (!DataFrag.getFixups().empty()) | |
1084 report_fatal_error("fixups not supported in .global_variables"); | |
1085 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); | |
1086 for (const uint8_t *p = (const uint8_t *)Contents.data(), | |
1087 *end = (const uint8_t *)Contents.data() + Contents.size(); | |
1088 p != end; ) { | |
1089 WasmGlobal G; | |
1090 if (end - p < 3) | |
1091 report_fatal_error("truncated global variable encoding"); | |
1092 G.Type = wasm::ValType(int8_t(*p++)); | |
1093 G.IsMutable = bool(*p++); | |
1094 G.HasImport = bool(*p++); | |
1095 if (G.HasImport) { | |
1096 G.InitialValue = 0; | |
1097 | |
1098 WasmImport Import; | |
1099 Import.ModuleName = (const char *)p; | |
1100 const uint8_t *nul = (const uint8_t *)memchr(p, '\0', end - p); | |
1101 if (!nul) | |
1102 report_fatal_error("global module name must be nul-terminated"); | |
1103 p = nul + 1; | |
1104 nul = (const uint8_t *)memchr(p, '\0', end - p); | |
1105 if (!nul) | |
1106 report_fatal_error("global base name must be nul-terminated"); | |
1107 Import.FieldName = (const char *)p; | |
1108 p = nul + 1; | |
1109 | |
1110 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; | |
1111 Import.Type = int32_t(G.Type); | |
1112 | |
1113 G.ImportIndex = NumGlobalImports; | |
1114 ++NumGlobalImports; | |
1115 | |
1116 Imports.push_back(Import); | |
1117 } else { | |
1118 unsigned n; | |
1119 G.InitialValue = decodeSLEB128(p, &n); | |
1120 G.ImportIndex = 0; | |
1121 if ((ptrdiff_t)n > end - p) | |
1122 report_fatal_error("global initial value must be valid SLEB128"); | |
1123 p += n; | |
1124 } | |
1125 Globals.push_back(G); | |
1126 } | |
1127 } | |
1128 | |
1129 // In the special .stack_pointer section, we've encoded the stack pointer | |
1130 // index. | |
1131 MCSectionWasm *StackPtr = | |
1132 Ctx.getWasmSection(".stack_pointer", SectionKind::getMetadata()); | |
1133 if (!StackPtr->getFragmentList().empty()) { | |
1134 if (StackPtr->getFragmentList().size() != 1) | |
1135 report_fatal_error("only one .stack_pointer fragment supported"); | |
1136 const MCFragment &Frag = *StackPtr->begin(); | |
1137 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) | |
1138 report_fatal_error("only data supported in .stack_pointer"); | |
1139 const auto &DataFrag = cast<MCDataFragment>(Frag); | |
1140 if (!DataFrag.getFixups().empty()) | |
1141 report_fatal_error("fixups not supported in .stack_pointer"); | |
1142 const SmallVectorImpl<char> &Contents = DataFrag.getContents(); | |
1143 if (Contents.size() != 4) | |
1144 report_fatal_error("only one entry supported in .stack_pointer"); | |
1145 HasStackPointer = true; | |
1146 StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); | |
1147 } | |
1148 | |
1149 for (MCSection &Sec : Asm) { | |
1150 auto &Section = static_cast<MCSectionWasm &>(Sec); | |
1151 if (!Section.isWasmData()) | |
1152 continue; | |
1153 | |
1154 DataSize = alignTo(DataSize, Section.getAlignment()); | |
1155 DataSegments.emplace_back(); | |
1156 WasmDataSegment &Segment = DataSegments.back(); | |
1157 Segment.Name = Section.getSectionName(); | |
1158 Segment.Offset = DataSize; | |
1159 Segment.Section = &Section; | |
1160 addData(Segment.Data, Section); | |
1161 Segment.Alignment = Section.getAlignment(); | |
1162 Segment.Flags = 0; | |
1163 DataSize += Segment.Data.size(); | |
1164 Section.setMemoryOffset(Segment.Offset); | |
1165 } | |
1166 | |
1167 // Handle regular defined and undefined symbols. | |
1168 for (const MCSymbol &S : Asm.symbols()) { | |
1169 // Ignore unnamed temporary symbols, which aren't ever exported, imported, | |
1170 // or used in relocations. | |
1171 if (S.isTemporary() && S.getName().empty()) | |
1172 continue; | |
1173 | |
1174 const auto &WS = static_cast<const MCSymbolWasm &>(S); | |
1175 DEBUG(dbgs() << "MCSymbol: '" << S << "'" | |
1176 << " isDefined=" << S.isDefined() << " isExternal=" | |
1177 << S.isExternal() << " isTemporary=" << S.isTemporary() | |
1178 << " isFunction=" << WS.isFunction() | |
1179 << " isWeak=" << WS.isWeak() | |
1180 << " isVariable=" << WS.isVariable() << "\n"); | |
1181 | |
1182 if (WS.isWeak()) | |
1183 SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_WEAK); | |
1184 | |
1185 if (WS.isVariable()) | |
1186 continue; | |
1187 | |
1188 unsigned Index; | |
1189 | |
1190 if (WS.isFunction()) { | |
1191 if (WS.isDefined(/*SetUsed=*/false)) { | |
1192 if (WS.getOffset() != 0) | |
1193 report_fatal_error( | |
1194 "function sections must contain one function each"); | |
1195 | |
1196 if (WS.getSize() == 0) | |
1197 report_fatal_error( | |
1198 "function symbols must have a size set with .size"); | |
1199 | |
1200 // A definition. Take the next available index. | |
1201 Index = NumFuncImports + Functions.size(); | |
1202 | |
1203 // Prepare the function. | |
1204 WasmFunction Func; | |
1205 Func.Type = getFunctionType(WS); | |
1206 Func.Sym = &WS; | |
1207 SymbolIndices[&WS] = Index; | |
1208 Functions.push_back(Func); | |
1209 } else { | |
1210 // An import; the index was assigned above. | |
1211 Index = SymbolIndices.find(&WS)->second; | |
1212 } | |
1213 | |
1214 DEBUG(dbgs() << " -> function index: " << Index << "\n"); | |
1215 | |
1216 // If needed, prepare the function to be called indirectly. | |
1217 if (IsAddressTaken.count(&WS) != 0) { | |
1218 IndirectSymbolIndices[&WS] = TableElems.size(); | |
1219 DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n"); | |
1220 TableElems.push_back(Index); | |
1221 } | |
1222 } else { | |
1223 if (WS.isTemporary() && !WS.getSize()) | |
1224 continue; | |
1225 | |
1226 if (!WS.isDefined(/*SetUsed=*/false)) | |
1227 continue; | |
1228 | |
1229 if (!WS.getSize()) | |
1230 report_fatal_error("data symbols must have a size set with .size: " + | |
1231 WS.getName()); | |
1232 | |
1233 int64_t Size = 0; | |
1234 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) | |
1235 report_fatal_error(".size expression must be evaluatable"); | |
1236 | |
1237 // For each global, prepare a corresponding wasm global holding its | |
1238 // address. For externals these will also be named exports. | |
1239 Index = NumGlobalImports + Globals.size(); | |
1240 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); | |
1241 | |
1242 WasmGlobal Global; | |
1243 Global.Type = PtrType; | |
1244 Global.IsMutable = false; | |
1245 Global.HasImport = false; | |
1246 Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); | |
1247 Global.ImportIndex = 0; | |
1248 SymbolIndices[&WS] = Index; | |
1249 DEBUG(dbgs() << " -> global index: " << Index << "\n"); | |
1250 Globals.push_back(Global); | |
1251 } | |
1252 | |
1253 // If the symbol is visible outside this translation unit, export it. | |
1254 if (WS.isDefined(/*SetUsed=*/false)) { | |
1255 WasmExport Export; | |
1256 Export.FieldName = WS.getName(); | |
1257 Export.Index = Index; | |
1258 if (WS.isFunction()) | |
1259 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; | |
1260 else | |
1261 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; | |
1262 DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); | |
1263 Exports.push_back(Export); | |
1264 if (!WS.isExternal()) | |
1265 SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); | |
1266 } | |
1267 } | |
1268 | |
1269 // Handle weak aliases. We need to process these in a separate pass because | |
1270 // we need to have processed the target of the alias before the alias itself | |
1271 // and the symbols are not necessarily ordered in this way. | |
1272 for (const MCSymbol &S : Asm.symbols()) { | |
1273 if (!S.isVariable()) | |
1274 continue; | |
1275 | |
1276 assert(S.isDefined(/*SetUsed=*/false)); | |
1277 | |
1278 // Find the target symbol of this weak alias and export that index | |
1279 const auto &WS = static_cast<const MCSymbolWasm &>(S); | |
1280 const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); | |
1281 DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); | |
1282 assert(SymbolIndices.count(ResolvedSym) > 0); | |
1283 uint32_t Index = SymbolIndices.find(ResolvedSym)->second; | |
1284 DEBUG(dbgs() << " -> index:" << Index << "\n"); | |
1285 | |
1286 SymbolIndices[&WS] = Index; | |
1287 WasmExport Export; | |
1288 Export.FieldName = WS.getName(); | |
1289 Export.Index = Index; | |
1290 if (WS.isFunction()) | |
1291 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; | |
1292 else | |
1293 Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; | |
1294 DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); | |
1295 Exports.push_back(Export); | |
1296 | |
1297 if (!WS.isExternal()) | |
1298 SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); | |
1299 } | |
1300 | |
1301 // Add types for indirect function calls. | |
1302 for (const WasmRelocationEntry &Fixup : CodeRelocations) { | |
1303 if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) | |
1304 continue; | |
1305 | |
1306 registerFunctionType(*Fixup.Symbol); | |
1307 } | |
1308 | |
1309 // Write out the Wasm header. | |
1310 writeHeader(Asm); | |
1311 | |
1312 writeTypeSection(FunctionTypes); | |
1313 writeImportSection(Imports); | |
1314 writeFunctionSection(Functions); | |
1315 writeTableSection(TableElems.size()); | |
1316 writeMemorySection(DataSize); | |
1317 writeGlobalSection(); | |
1318 writeExportSection(Exports); | |
1319 // TODO: Start Section | |
1320 writeElemSection(TableElems); | |
1321 writeCodeSection(Asm, Layout, Functions); | |
1322 writeDataSection(DataSegments); | |
1323 writeNameSection(Functions, Imports, NumFuncImports); | |
1324 writeCodeRelocSection(); | |
1325 writeDataRelocSection(); | |
1326 writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, | |
1327 HasStackPointer, StackPointerGlobal); | |
1328 | |
1329 // TODO: Translate the .comment section to the output. | |
1330 // TODO: Translate debug sections to the output. | |
1331 } | |
1332 | |
1333 std::unique_ptr<MCObjectWriter> | |
1334 llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW, | |
1335 raw_pwrite_stream &OS) { | |
1336 // FIXME: Can't use make_unique<WasmObjectWriter>(...) as WasmObjectWriter's | |
1337 // destructor is private. Is that necessary? | |
1338 return std::unique_ptr<MCObjectWriter>( | |
1339 new WasmObjectWriter(std::move(MOTW), OS)); | |
1340 } |