1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements Wasm object file writer information.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/SmallPtrSet.h"
15 #include "llvm/BinaryFormat/Wasm.h"
16 #include "llvm/Config/llvm-config.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAsmLayout.h"
19 #include "llvm/MC/MCAssembler.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCFixupKindInfo.h"
23 #include "llvm/MC/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"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/LEB128.h"
32 #include "llvm/Support/StringSaver.h"
33 #include <vector>
34
35 using namespace llvm;
36
37 #define DEBUG_TYPE "mc"
38
39 namespace {
40
41 // 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.
43 static const uint32_t InitialTableOffset = 1;
44
45 // 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.
48 struct SectionBookkeeping {
49 // Where the size of the section is written.
50 uint64_t SizeOffset;
51 // Where the section header ends (without custom section name).
52 uint64_t PayloadOffset;
53 // Where the contents of the section starts.
54 uint64_t ContentsOffset;
55 uint32_t Index;
56 };
57
58 // The signature of a wasm function or event, in a struct capable of being used
59 // as a DenseMap key.
60 // TODO: Consider using wasm::WasmSignature directly instead.
61 struct WasmSignature {
62 // Support empty and tombstone instances, needed by DenseMap.
63 enum { Plain, Empty, Tombstone } State = Plain;
64
65 // The return types of the function.
66 SmallVector<wasm::ValType, 1> Returns;
67
68 // The parameter types of the function.
69 SmallVector<wasm::ValType, 4> Params;
70
operator ==__anon05dc5c860111::WasmSignature71 bool operator==(const WasmSignature &Other) const {
72 return State == Other.State && Returns == Other.Returns &&
73 Params == Other.Params;
74 }
75 };
76
77 // Traits for using WasmSignature in a DenseMap.
78 struct WasmSignatureDenseMapInfo {
getEmptyKey__anon05dc5c860111::WasmSignatureDenseMapInfo79 static WasmSignature getEmptyKey() {
80 WasmSignature Sig;
81 Sig.State = WasmSignature::Empty;
82 return Sig;
83 }
getTombstoneKey__anon05dc5c860111::WasmSignatureDenseMapInfo84 static WasmSignature getTombstoneKey() {
85 WasmSignature Sig;
86 Sig.State = WasmSignature::Tombstone;
87 return Sig;
88 }
getHashValue__anon05dc5c860111::WasmSignatureDenseMapInfo89 static unsigned getHashValue(const WasmSignature &Sig) {
90 uintptr_t Value = Sig.State;
91 for (wasm::ValType Ret : Sig.Returns)
92 Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Ret));
93 for (wasm::ValType Param : Sig.Params)
94 Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Param));
95 return Value;
96 }
isEqual__anon05dc5c860111::WasmSignatureDenseMapInfo97 static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) {
98 return LHS == RHS;
99 }
100 };
101
102 // 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.
106 struct WasmDataSegment {
107 MCSectionWasm *Section;
108 StringRef Name;
109 uint32_t InitFlags;
110 uint32_t Offset;
111 uint32_t Alignment;
112 uint32_t LinkerFlags;
113 SmallVector<char, 4> Data;
114 };
115
116 // A wasm function to be written into the function section.
117 struct WasmFunction {
118 uint32_t SigIndex;
119 const MCSymbolWasm *Sym;
120 };
121
122 // A wasm global to be written into the global section.
123 struct WasmGlobal {
124 wasm::WasmGlobalType Type;
125 uint64_t InitialValue;
126 };
127
128 // Information about a single item which is part of a COMDAT. For each data
129 // segment or function which is in the COMDAT, there is a corresponding
130 // WasmComdatEntry.
131 struct WasmComdatEntry {
132 unsigned Kind;
133 uint32_t Index;
134 };
135
136 // Information about a single relocation.
137 struct WasmRelocationEntry {
138 uint64_t Offset; // Where is the relocation.
139 const MCSymbolWasm *Symbol; // The symbol to relocate with.
140 int64_t Addend; // A value to add to the symbol.
141 unsigned Type; // The type of the relocation.
142 const MCSectionWasm *FixupSection; // The section the relocation is targeting.
143
WasmRelocationEntry__anon05dc5c860111::WasmRelocationEntry144 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
145 int64_t Addend, unsigned Type,
146 const MCSectionWasm *FixupSection)
147 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
148 FixupSection(FixupSection) {}
149
hasAddend__anon05dc5c860111::WasmRelocationEntry150 bool hasAddend() const { return wasm::relocTypeHasAddend(Type); }
151
print__anon05dc5c860111::WasmRelocationEntry152 void print(raw_ostream &Out) const {
153 Out << wasm::relocTypetoString(Type) << " Off=" << Offset
154 << ", Sym=" << *Symbol << ", Addend=" << Addend
155 << ", FixupSection=" << FixupSection->getSectionName();
156 }
157
158 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump__anon05dc5c860111::WasmRelocationEntry159 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
160 #endif
161 };
162
163 static const uint32_t InvalidIndex = -1;
164
165 struct WasmCustomSection {
166
167 StringRef Name;
168 MCSectionWasm *Section;
169
170 uint32_t OutputContentsOffset;
171 uint32_t OutputIndex;
172
WasmCustomSection__anon05dc5c860111::WasmCustomSection173 WasmCustomSection(StringRef Name, MCSectionWasm *Section)
174 : Name(Name), Section(Section), OutputContentsOffset(0),
175 OutputIndex(InvalidIndex) {}
176 };
177
178 #if !defined(NDEBUG)
operator <<(raw_ostream & OS,const WasmRelocationEntry & Rel)179 raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
180 Rel.print(OS);
181 return OS;
182 }
183 #endif
184
185 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
186 // to allow patching.
writePatchableLEB(raw_pwrite_stream & Stream,uint32_t X,uint64_t Offset)187 static void writePatchableLEB(raw_pwrite_stream &Stream, uint32_t X,
188 uint64_t Offset) {
189 uint8_t Buffer[5];
190 unsigned SizeLen = encodeULEB128(X, Buffer, 5);
191 assert(SizeLen == 5);
192 Stream.pwrite((char *)Buffer, SizeLen, Offset);
193 }
194
195 // Write X as an signed LEB value at offset Offset in Stream, padded
196 // to allow patching.
writePatchableSLEB(raw_pwrite_stream & Stream,int32_t X,uint64_t Offset)197 static void writePatchableSLEB(raw_pwrite_stream &Stream, int32_t X,
198 uint64_t Offset) {
199 uint8_t Buffer[5];
200 unsigned SizeLen = encodeSLEB128(X, Buffer, 5);
201 assert(SizeLen == 5);
202 Stream.pwrite((char *)Buffer, SizeLen, Offset);
203 }
204
205 // Write X as a plain integer value at offset Offset in Stream.
writeI32(raw_pwrite_stream & Stream,uint32_t X,uint64_t Offset)206 static void writeI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
207 uint8_t Buffer[4];
208 support::endian::write32le(Buffer, X);
209 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
210 }
211
212 class WasmObjectWriter : public MCObjectWriter {
213 support::endian::Writer W;
214
215 /// The target specific Wasm writer instance.
216 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
217
218 // Relocations for fixing up references in the code section.
219 std::vector<WasmRelocationEntry> CodeRelocations;
220 uint32_t CodeSectionIndex;
221
222 // Relocations for fixing up references in the data section.
223 std::vector<WasmRelocationEntry> DataRelocations;
224 uint32_t DataSectionIndex;
225
226 // Index values to use for fixing up call_indirect type indices.
227 // Maps function symbols to the index of the type of the function
228 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
229 // Maps function symbols to the table element index space. Used
230 // for TABLE_INDEX relocation types (i.e. address taken functions).
231 DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
232 // Maps function/global symbols to the function/global/event/section index
233 // space.
234 DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
235 DenseMap<const MCSymbolWasm *, uint32_t> GOTIndices;
236 // Maps data symbols to the Wasm segment and offset/size with the segment.
237 DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
238
239 // Stores output data (index, relocations, content offset) for custom
240 // section.
241 std::vector<WasmCustomSection> CustomSections;
242 std::unique_ptr<WasmCustomSection> ProducersSection;
243 std::unique_ptr<WasmCustomSection> TargetFeaturesSection;
244 // Relocations for fixing up references in the custom sections.
245 DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
246 CustomSectionsRelocations;
247
248 // Map from section to defining function symbol.
249 DenseMap<const MCSection *, const MCSymbol *> SectionFunctions;
250
251 DenseMap<WasmSignature, uint32_t, WasmSignatureDenseMapInfo> SignatureIndices;
252 SmallVector<WasmSignature, 4> Signatures;
253 SmallVector<WasmDataSegment, 4> DataSegments;
254 unsigned NumFunctionImports = 0;
255 unsigned NumGlobalImports = 0;
256 unsigned NumEventImports = 0;
257 uint32_t SectionCount = 0;
258
259 // TargetObjectWriter wrappers.
is64Bit() const260 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
isEmscripten() const261 bool isEmscripten() const { return TargetObjectWriter->isEmscripten(); }
262
263 void startSection(SectionBookkeeping &Section, unsigned SectionId);
264 void startCustomSection(SectionBookkeeping &Section, StringRef Name);
265 void endSection(SectionBookkeeping &Section);
266
267 public:
WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,raw_pwrite_stream & OS)268 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
269 raw_pwrite_stream &OS)
270 : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {}
271
272 private:
reset()273 void reset() override {
274 CodeRelocations.clear();
275 DataRelocations.clear();
276 TypeIndices.clear();
277 WasmIndices.clear();
278 GOTIndices.clear();
279 TableIndices.clear();
280 DataLocations.clear();
281 CustomSections.clear();
282 ProducersSection.reset();
283 TargetFeaturesSection.reset();
284 CustomSectionsRelocations.clear();
285 SignatureIndices.clear();
286 Signatures.clear();
287 DataSegments.clear();
288 SectionFunctions.clear();
289 NumFunctionImports = 0;
290 NumGlobalImports = 0;
291 MCObjectWriter::reset();
292 }
293
294 void writeHeader(const MCAssembler &Asm);
295
296 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
297 const MCFragment *Fragment, const MCFixup &Fixup,
298 MCValue Target, uint64_t &FixedValue) override;
299
300 void executePostLayoutBinding(MCAssembler &Asm,
301 const MCAsmLayout &Layout) override;
302
303 uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
304
writeString(const StringRef Str)305 void writeString(const StringRef Str) {
306 encodeULEB128(Str.size(), W.OS);
307 W.OS << Str;
308 }
309
writeValueType(wasm::ValType Ty)310 void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
311
312 void writeTypeSection(ArrayRef<WasmSignature> Signatures);
313 void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
314 uint32_t NumElements);
315 void writeFunctionSection(ArrayRef<WasmFunction> Functions);
316 void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
317 void writeElemSection(ArrayRef<uint32_t> TableElems);
318 void writeDataCountSection();
319 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
320 ArrayRef<WasmFunction> Functions);
321 void writeDataSection();
322 void writeEventSection(ArrayRef<wasm::WasmEventType> Events);
323 void writeRelocSection(uint32_t SectionIndex, StringRef Name,
324 std::vector<WasmRelocationEntry> &Relocations);
325 void writeLinkingMetaDataSection(
326 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
327 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
328 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
329 void writeCustomSection(WasmCustomSection &CustomSection,
330 const MCAssembler &Asm, const MCAsmLayout &Layout);
331 void writeCustomRelocSections();
332 void
333 updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions,
334 const MCAsmLayout &Layout);
335
336 uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
337 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
338 uint64_t ContentsOffset);
339
340 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
341 uint32_t getFunctionType(const MCSymbolWasm &Symbol);
342 uint32_t getEventType(const MCSymbolWasm &Symbol);
343 void registerFunctionType(const MCSymbolWasm &Symbol);
344 void registerEventType(const MCSymbolWasm &Symbol);
345 };
346
347 } // end anonymous namespace
348
349 // Write out a section header and a patchable section size field.
startSection(SectionBookkeeping & Section,unsigned SectionId)350 void WasmObjectWriter::startSection(SectionBookkeeping &Section,
351 unsigned SectionId) {
352 LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n");
353 W.OS << char(SectionId);
354
355 Section.SizeOffset = W.OS.tell();
356
357 // The section size. We don't know the size yet, so reserve enough space
358 // for any 32-bit value; we'll patch it later.
359 encodeULEB128(0, W.OS, 5);
360
361 // The position where the section starts, for measuring its size.
362 Section.ContentsOffset = W.OS.tell();
363 Section.PayloadOffset = W.OS.tell();
364 Section.Index = SectionCount++;
365 }
366
startCustomSection(SectionBookkeeping & Section,StringRef Name)367 void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
368 StringRef Name) {
369 LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n");
370 startSection(Section, wasm::WASM_SEC_CUSTOM);
371
372 // The position where the section header ends, for measuring its size.
373 Section.PayloadOffset = W.OS.tell();
374
375 // Custom sections in wasm also have a string identifier.
376 writeString(Name);
377
378 // The position where the custom section starts.
379 Section.ContentsOffset = W.OS.tell();
380 }
381
382 // Now that the section is complete and we know how big it is, patch up the
383 // section size field at the start of the section.
endSection(SectionBookkeeping & Section)384 void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
385 uint64_t Size = W.OS.tell();
386 // /dev/null doesn't support seek/tell and can report offset of 0.
387 // Simply skip this patching in that case.
388 if (!Size)
389 return;
390
391 Size -= Section.PayloadOffset;
392 if (uint32_t(Size) != Size)
393 report_fatal_error("section size does not fit in a uint32_t");
394
395 LLVM_DEBUG(dbgs() << "endSection size=" << Size << "\n");
396
397 // Write the final section size to the payload_len field, which follows
398 // the section id byte.
399 writePatchableLEB(static_cast<raw_pwrite_stream &>(W.OS), Size,
400 Section.SizeOffset);
401 }
402
403 // Emit the Wasm header.
writeHeader(const MCAssembler & Asm)404 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
405 W.OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
406 W.write<uint32_t>(wasm::WasmVersion);
407 }
408
executePostLayoutBinding(MCAssembler & Asm,const MCAsmLayout & Layout)409 void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
410 const MCAsmLayout &Layout) {
411 // Build a map of sections to the function that defines them, for use
412 // in recordRelocation.
413 for (const MCSymbol &S : Asm.symbols()) {
414 const auto &WS = static_cast<const MCSymbolWasm &>(S);
415 if (WS.isDefined() && WS.isFunction() && !WS.isVariable()) {
416 const auto &Sec = static_cast<const MCSectionWasm &>(S.getSection());
417 auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S));
418 if (!Pair.second)
419 report_fatal_error("section already has a defining function: " +
420 Sec.getSectionName());
421 }
422 }
423 }
424
recordRelocation(MCAssembler & Asm,const MCAsmLayout & Layout,const MCFragment * Fragment,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)425 void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
426 const MCAsmLayout &Layout,
427 const MCFragment *Fragment,
428 const MCFixup &Fixup, MCValue Target,
429 uint64_t &FixedValue) {
430 // The WebAssembly backend should never generate FKF_IsPCRel fixups
431 assert(!(Asm.getBackend().getFixupKindInfo(Fixup.getKind()).Flags &
432 MCFixupKindInfo::FKF_IsPCRel));
433
434 const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
435 uint64_t C = Target.getConstant();
436 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
437 MCContext &Ctx = Asm.getContext();
438
439 // The .init_array isn't translated as data, so don't do relocations in it.
440 if (FixupSection.getSectionName().startswith(".init_array"))
441 return;
442
443 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
444 // To get here the A - B expression must have failed evaluateAsRelocatable.
445 // This means either A or B must be undefined and in WebAssembly we can't
446 // support either of those cases.
447 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
448 Ctx.reportError(
449 Fixup.getLoc(),
450 Twine("symbol '") + SymB.getName() +
451 "': unsupported subtraction expression used in relocation.");
452 return;
453 }
454
455 // We either rejected the fixup or folded B into C at this point.
456 const MCSymbolRefExpr *RefA = Target.getSymA();
457 const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol());
458
459 if (SymA->isVariable()) {
460 const MCExpr *Expr = SymA->getVariableValue();
461 const auto *Inner = cast<MCSymbolRefExpr>(Expr);
462 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
463 llvm_unreachable("weakref used in reloc not yet implemented");
464 }
465
466 // Put any constant offset in an addend. Offsets can be negative, and
467 // LLVM expects wrapping, in contrast to wasm's immediates which can't
468 // be negative and don't wrap.
469 FixedValue = 0;
470
471 unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup);
472
473 // Absolute offset within a section or a function.
474 // Currently only supported for for metadata sections.
475 // See: test/MC/WebAssembly/blockaddress.ll
476 if (Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
477 Type == wasm::R_WASM_SECTION_OFFSET_I32) {
478 if (!FixupSection.getKind().isMetadata())
479 report_fatal_error("relocations for function or section offsets are "
480 "only supported in metadata sections");
481
482 const MCSymbol *SectionSymbol = nullptr;
483 const MCSection &SecA = SymA->getSection();
484 if (SecA.getKind().isText())
485 SectionSymbol = SectionFunctions.find(&SecA)->second;
486 else
487 SectionSymbol = SecA.getBeginSymbol();
488 if (!SectionSymbol)
489 report_fatal_error("section symbol is required for relocation");
490
491 C += Layout.getSymbolOffset(*SymA);
492 SymA = cast<MCSymbolWasm>(SectionSymbol);
493 }
494
495 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
496 // against a named symbol.
497 if (Type != wasm::R_WASM_TYPE_INDEX_LEB) {
498 if (SymA->getName().empty())
499 report_fatal_error("relocations against un-named temporaries are not yet "
500 "supported by wasm");
501
502 SymA->setUsedInReloc();
503 }
504
505 if (RefA->getKind() == MCSymbolRefExpr::VK_GOT)
506 SymA->setUsedInGOT();
507
508 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
509 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
510
511 if (FixupSection.isWasmData()) {
512 DataRelocations.push_back(Rec);
513 } else if (FixupSection.getKind().isText()) {
514 CodeRelocations.push_back(Rec);
515 } else if (FixupSection.getKind().isMetadata()) {
516 CustomSectionsRelocations[&FixupSection].push_back(Rec);
517 } else {
518 llvm_unreachable("unexpected section type");
519 }
520 }
521
resolveSymbol(const MCSymbolWasm & Symbol)522 static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) {
523 const MCSymbolWasm* Ret = &Symbol;
524 while (Ret->isVariable()) {
525 const MCExpr *Expr = Ret->getVariableValue();
526 auto *Inner = cast<MCSymbolRefExpr>(Expr);
527 Ret = cast<MCSymbolWasm>(&Inner->getSymbol());
528 }
529 return Ret;
530 }
531
532 // Compute a value to write into the code at the location covered
533 // by RelEntry. This value isn't used by the static linker; it just serves
534 // to make the object format more readable and more likely to be directly
535 // useable.
536 uint32_t
getProvisionalValue(const WasmRelocationEntry & RelEntry)537 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
538 if (RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB && !RelEntry.Symbol->isGlobal()) {
539 assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space");
540 return GOTIndices[RelEntry.Symbol];
541 }
542
543 switch (RelEntry.Type) {
544 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
545 case wasm::R_WASM_TABLE_INDEX_SLEB:
546 case wasm::R_WASM_TABLE_INDEX_I32: {
547 // Provisional value is table address of the resolved symbol itself
548 const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
549 assert(Sym->isFunction());
550 return TableIndices[Sym];
551 }
552 case wasm::R_WASM_TYPE_INDEX_LEB:
553 // Provisional value is same as the index
554 return getRelocationIndexValue(RelEntry);
555 case wasm::R_WASM_FUNCTION_INDEX_LEB:
556 case wasm::R_WASM_GLOBAL_INDEX_LEB:
557 case wasm::R_WASM_EVENT_INDEX_LEB:
558 // Provisional value is function/global/event Wasm index
559 assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
560 return WasmIndices[RelEntry.Symbol];
561 case wasm::R_WASM_FUNCTION_OFFSET_I32:
562 case wasm::R_WASM_SECTION_OFFSET_I32: {
563 const auto &Section =
564 static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
565 return Section.getSectionOffset() + RelEntry.Addend;
566 }
567 case wasm::R_WASM_MEMORY_ADDR_LEB:
568 case wasm::R_WASM_MEMORY_ADDR_I32:
569 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
570 case wasm::R_WASM_MEMORY_ADDR_SLEB: {
571 // Provisional value is address of the global
572 const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
573 // For undefined symbols, use zero
574 if (!Sym->isDefined())
575 return 0;
576 const wasm::WasmDataReference &Ref = DataLocations[Sym];
577 const WasmDataSegment &Segment = DataSegments[Ref.Segment];
578 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
579 return Segment.Offset + Ref.Offset + RelEntry.Addend;
580 }
581 default:
582 llvm_unreachable("invalid relocation type");
583 }
584 }
585
addData(SmallVectorImpl<char> & DataBytes,MCSectionWasm & DataSection)586 static void addData(SmallVectorImpl<char> &DataBytes,
587 MCSectionWasm &DataSection) {
588 LLVM_DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
589
590 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
591
592 for (const MCFragment &Frag : DataSection) {
593 if (Frag.hasInstructions())
594 report_fatal_error("only data supported in data sections");
595
596 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
597 if (Align->getValueSize() != 1)
598 report_fatal_error("only byte values supported for alignment");
599 // If nops are requested, use zeros, as this is the data section.
600 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
601 uint64_t Size =
602 std::min<uint64_t>(alignTo(DataBytes.size(), Align->getAlignment()),
603 DataBytes.size() + Align->getMaxBytesToEmit());
604 DataBytes.resize(Size, Value);
605 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
606 int64_t NumValues;
607 if (!Fill->getNumValues().evaluateAsAbsolute(NumValues))
608 llvm_unreachable("The fill should be an assembler constant");
609 DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues,
610 Fill->getValue());
611 } else if (auto *LEB = dyn_cast<MCLEBFragment>(&Frag)) {
612 const SmallVectorImpl<char> &Contents = LEB->getContents();
613 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
614 } else {
615 const auto &DataFrag = cast<MCDataFragment>(Frag);
616 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
617 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
618 }
619 }
620
621 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
622 }
623
624 uint32_t
getRelocationIndexValue(const WasmRelocationEntry & RelEntry)625 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
626 if (RelEntry.Type == wasm::R_WASM_TYPE_INDEX_LEB) {
627 if (!TypeIndices.count(RelEntry.Symbol))
628 report_fatal_error("symbol not found in type index space: " +
629 RelEntry.Symbol->getName());
630 return TypeIndices[RelEntry.Symbol];
631 }
632
633 return RelEntry.Symbol->getIndex();
634 }
635
636 // Apply the portions of the relocation records that we can handle ourselves
637 // directly.
applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,uint64_t ContentsOffset)638 void WasmObjectWriter::applyRelocations(
639 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
640 auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
641 for (const WasmRelocationEntry &RelEntry : Relocations) {
642 uint64_t Offset = ContentsOffset +
643 RelEntry.FixupSection->getSectionOffset() +
644 RelEntry.Offset;
645
646 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
647 uint32_t Value = getProvisionalValue(RelEntry);
648
649 switch (RelEntry.Type) {
650 case wasm::R_WASM_FUNCTION_INDEX_LEB:
651 case wasm::R_WASM_TYPE_INDEX_LEB:
652 case wasm::R_WASM_GLOBAL_INDEX_LEB:
653 case wasm::R_WASM_MEMORY_ADDR_LEB:
654 case wasm::R_WASM_EVENT_INDEX_LEB:
655 writePatchableLEB(Stream, Value, Offset);
656 break;
657 case wasm::R_WASM_TABLE_INDEX_I32:
658 case wasm::R_WASM_MEMORY_ADDR_I32:
659 case wasm::R_WASM_FUNCTION_OFFSET_I32:
660 case wasm::R_WASM_SECTION_OFFSET_I32:
661 writeI32(Stream, Value, Offset);
662 break;
663 case wasm::R_WASM_TABLE_INDEX_SLEB:
664 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
665 case wasm::R_WASM_MEMORY_ADDR_SLEB:
666 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
667 writePatchableSLEB(Stream, Value, Offset);
668 break;
669 default:
670 llvm_unreachable("invalid relocation type");
671 }
672 }
673 }
674
writeTypeSection(ArrayRef<WasmSignature> Signatures)675 void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
676 if (Signatures.empty())
677 return;
678
679 SectionBookkeeping Section;
680 startSection(Section, wasm::WASM_SEC_TYPE);
681
682 encodeULEB128(Signatures.size(), W.OS);
683
684 for (const WasmSignature &Sig : Signatures) {
685 W.OS << char(wasm::WASM_TYPE_FUNC);
686 encodeULEB128(Sig.Params.size(), W.OS);
687 for (wasm::ValType Ty : Sig.Params)
688 writeValueType(Ty);
689 encodeULEB128(Sig.Returns.size(), W.OS);
690 for (wasm::ValType Ty : Sig.Returns)
691 writeValueType(Ty);
692 }
693
694 endSection(Section);
695 }
696
writeImportSection(ArrayRef<wasm::WasmImport> Imports,uint32_t DataSize,uint32_t NumElements)697 void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
698 uint32_t DataSize,
699 uint32_t NumElements) {
700 if (Imports.empty())
701 return;
702
703 uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
704
705 SectionBookkeeping Section;
706 startSection(Section, wasm::WASM_SEC_IMPORT);
707
708 encodeULEB128(Imports.size(), W.OS);
709 for (const wasm::WasmImport &Import : Imports) {
710 writeString(Import.Module);
711 writeString(Import.Field);
712 W.OS << char(Import.Kind);
713
714 switch (Import.Kind) {
715 case wasm::WASM_EXTERNAL_FUNCTION:
716 encodeULEB128(Import.SigIndex, W.OS);
717 break;
718 case wasm::WASM_EXTERNAL_GLOBAL:
719 W.OS << char(Import.Global.Type);
720 W.OS << char(Import.Global.Mutable ? 1 : 0);
721 break;
722 case wasm::WASM_EXTERNAL_MEMORY:
723 encodeULEB128(0, W.OS); // flags
724 encodeULEB128(NumPages, W.OS); // initial
725 break;
726 case wasm::WASM_EXTERNAL_TABLE:
727 W.OS << char(Import.Table.ElemType);
728 encodeULEB128(0, W.OS); // flags
729 encodeULEB128(NumElements, W.OS); // initial
730 break;
731 case wasm::WASM_EXTERNAL_EVENT:
732 encodeULEB128(Import.Event.Attribute, W.OS);
733 encodeULEB128(Import.Event.SigIndex, W.OS);
734 break;
735 default:
736 llvm_unreachable("unsupported import kind");
737 }
738 }
739
740 endSection(Section);
741 }
742
writeFunctionSection(ArrayRef<WasmFunction> Functions)743 void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
744 if (Functions.empty())
745 return;
746
747 SectionBookkeeping Section;
748 startSection(Section, wasm::WASM_SEC_FUNCTION);
749
750 encodeULEB128(Functions.size(), W.OS);
751 for (const WasmFunction &Func : Functions)
752 encodeULEB128(Func.SigIndex, W.OS);
753
754 endSection(Section);
755 }
756
writeEventSection(ArrayRef<wasm::WasmEventType> Events)757 void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
758 if (Events.empty())
759 return;
760
761 SectionBookkeeping Section;
762 startSection(Section, wasm::WASM_SEC_EVENT);
763
764 encodeULEB128(Events.size(), W.OS);
765 for (const wasm::WasmEventType &Event : Events) {
766 encodeULEB128(Event.Attribute, W.OS);
767 encodeULEB128(Event.SigIndex, W.OS);
768 }
769
770 endSection(Section);
771 }
772
writeExportSection(ArrayRef<wasm::WasmExport> Exports)773 void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
774 if (Exports.empty())
775 return;
776
777 SectionBookkeeping Section;
778 startSection(Section, wasm::WASM_SEC_EXPORT);
779
780 encodeULEB128(Exports.size(), W.OS);
781 for (const wasm::WasmExport &Export : Exports) {
782 writeString(Export.Name);
783 W.OS << char(Export.Kind);
784 encodeULEB128(Export.Index, W.OS);
785 }
786
787 endSection(Section);
788 }
789
writeElemSection(ArrayRef<uint32_t> TableElems)790 void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
791 if (TableElems.empty())
792 return;
793
794 SectionBookkeeping Section;
795 startSection(Section, wasm::WASM_SEC_ELEM);
796
797 encodeULEB128(1, W.OS); // number of "segments"
798 encodeULEB128(0, W.OS); // the table index
799
800 // init expr for starting offset
801 W.OS << char(wasm::WASM_OPCODE_I32_CONST);
802 encodeSLEB128(InitialTableOffset, W.OS);
803 W.OS << char(wasm::WASM_OPCODE_END);
804
805 encodeULEB128(TableElems.size(), W.OS);
806 for (uint32_t Elem : TableElems)
807 encodeULEB128(Elem, W.OS);
808
809 endSection(Section);
810 }
811
writeDataCountSection()812 void WasmObjectWriter::writeDataCountSection() {
813 if (DataSegments.empty())
814 return;
815
816 SectionBookkeeping Section;
817 startSection(Section, wasm::WASM_SEC_DATACOUNT);
818 encodeULEB128(DataSegments.size(), W.OS);
819 endSection(Section);
820 }
821
writeCodeSection(const MCAssembler & Asm,const MCAsmLayout & Layout,ArrayRef<WasmFunction> Functions)822 void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
823 const MCAsmLayout &Layout,
824 ArrayRef<WasmFunction> Functions) {
825 if (Functions.empty())
826 return;
827
828 SectionBookkeeping Section;
829 startSection(Section, wasm::WASM_SEC_CODE);
830 CodeSectionIndex = Section.Index;
831
832 encodeULEB128(Functions.size(), W.OS);
833
834 for (const WasmFunction &Func : Functions) {
835 auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection());
836
837 int64_t Size = 0;
838 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
839 report_fatal_error(".size expression must be evaluatable");
840
841 encodeULEB128(Size, W.OS);
842 FuncSection.setSectionOffset(W.OS.tell() - Section.ContentsOffset);
843 Asm.writeSectionData(W.OS, &FuncSection, Layout);
844 }
845
846 // Apply fixups.
847 applyRelocations(CodeRelocations, Section.ContentsOffset);
848
849 endSection(Section);
850 }
851
writeDataSection()852 void WasmObjectWriter::writeDataSection() {
853 if (DataSegments.empty())
854 return;
855
856 SectionBookkeeping Section;
857 startSection(Section, wasm::WASM_SEC_DATA);
858 DataSectionIndex = Section.Index;
859
860 encodeULEB128(DataSegments.size(), W.OS); // count
861
862 for (const WasmDataSegment &Segment : DataSegments) {
863 encodeULEB128(Segment.InitFlags, W.OS); // flags
864 if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
865 encodeULEB128(0, W.OS); // memory index
866 if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
867 W.OS << char(wasm::WASM_OPCODE_I32_CONST);
868 encodeSLEB128(Segment.Offset, W.OS); // offset
869 W.OS << char(wasm::WASM_OPCODE_END);
870 }
871 encodeULEB128(Segment.Data.size(), W.OS); // size
872 Segment.Section->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
873 W.OS << Segment.Data; // data
874 }
875
876 // Apply fixups.
877 applyRelocations(DataRelocations, Section.ContentsOffset);
878
879 endSection(Section);
880 }
881
writeRelocSection(uint32_t SectionIndex,StringRef Name,std::vector<WasmRelocationEntry> & Relocs)882 void WasmObjectWriter::writeRelocSection(
883 uint32_t SectionIndex, StringRef Name,
884 std::vector<WasmRelocationEntry> &Relocs) {
885 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
886 // for descriptions of the reloc sections.
887
888 if (Relocs.empty())
889 return;
890
891 // First, ensure the relocations are sorted in offset order. In general they
892 // should already be sorted since `recordRelocation` is called in offset
893 // order, but for the code section we combine many MC sections into single
894 // wasm section, and this order is determined by the order of Asm.Symbols()
895 // not the sections order.
896 llvm::stable_sort(
897 Relocs, [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) {
898 return (A.Offset + A.FixupSection->getSectionOffset()) <
899 (B.Offset + B.FixupSection->getSectionOffset());
900 });
901
902 SectionBookkeeping Section;
903 startCustomSection(Section, std::string("reloc.") + Name.str());
904
905 encodeULEB128(SectionIndex, W.OS);
906 encodeULEB128(Relocs.size(), W.OS);
907 for (const WasmRelocationEntry &RelEntry : Relocs) {
908 uint64_t Offset =
909 RelEntry.Offset + RelEntry.FixupSection->getSectionOffset();
910 uint32_t Index = getRelocationIndexValue(RelEntry);
911
912 W.OS << char(RelEntry.Type);
913 encodeULEB128(Offset, W.OS);
914 encodeULEB128(Index, W.OS);
915 if (RelEntry.hasAddend())
916 encodeSLEB128(RelEntry.Addend, W.OS);
917 }
918
919 endSection(Section);
920 }
921
writeCustomRelocSections()922 void WasmObjectWriter::writeCustomRelocSections() {
923 for (const auto &Sec : CustomSections) {
924 auto &Relocations = CustomSectionsRelocations[Sec.Section];
925 writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations);
926 }
927 }
928
writeLinkingMetaDataSection(ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,ArrayRef<std::pair<uint16_t,uint32_t>> InitFuncs,const std::map<StringRef,std::vector<WasmComdatEntry>> & Comdats)929 void WasmObjectWriter::writeLinkingMetaDataSection(
930 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
931 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
932 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
933 SectionBookkeeping Section;
934 startCustomSection(Section, "linking");
935 encodeULEB128(wasm::WasmMetadataVersion, W.OS);
936
937 SectionBookkeeping SubSection;
938 if (SymbolInfos.size() != 0) {
939 startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
940 encodeULEB128(SymbolInfos.size(), W.OS);
941 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
942 encodeULEB128(Sym.Kind, W.OS);
943 encodeULEB128(Sym.Flags, W.OS);
944 switch (Sym.Kind) {
945 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
946 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
947 case wasm::WASM_SYMBOL_TYPE_EVENT:
948 encodeULEB128(Sym.ElementIndex, W.OS);
949 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 ||
950 (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
951 writeString(Sym.Name);
952 break;
953 case wasm::WASM_SYMBOL_TYPE_DATA:
954 writeString(Sym.Name);
955 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
956 encodeULEB128(Sym.DataRef.Segment, W.OS);
957 encodeULEB128(Sym.DataRef.Offset, W.OS);
958 encodeULEB128(Sym.DataRef.Size, W.OS);
959 }
960 break;
961 case wasm::WASM_SYMBOL_TYPE_SECTION: {
962 const uint32_t SectionIndex =
963 CustomSections[Sym.ElementIndex].OutputIndex;
964 encodeULEB128(SectionIndex, W.OS);
965 break;
966 }
967 default:
968 llvm_unreachable("unexpected kind");
969 }
970 }
971 endSection(SubSection);
972 }
973
974 if (DataSegments.size()) {
975 startSection(SubSection, wasm::WASM_SEGMENT_INFO);
976 encodeULEB128(DataSegments.size(), W.OS);
977 for (const WasmDataSegment &Segment : DataSegments) {
978 writeString(Segment.Name);
979 encodeULEB128(Segment.Alignment, W.OS);
980 encodeULEB128(Segment.LinkerFlags, W.OS);
981 }
982 endSection(SubSection);
983 }
984
985 if (!InitFuncs.empty()) {
986 startSection(SubSection, wasm::WASM_INIT_FUNCS);
987 encodeULEB128(InitFuncs.size(), W.OS);
988 for (auto &StartFunc : InitFuncs) {
989 encodeULEB128(StartFunc.first, W.OS); // priority
990 encodeULEB128(StartFunc.second, W.OS); // function index
991 }
992 endSection(SubSection);
993 }
994
995 if (Comdats.size()) {
996 startSection(SubSection, wasm::WASM_COMDAT_INFO);
997 encodeULEB128(Comdats.size(), W.OS);
998 for (const auto &C : Comdats) {
999 writeString(C.first);
1000 encodeULEB128(0, W.OS); // flags for future use
1001 encodeULEB128(C.second.size(), W.OS);
1002 for (const WasmComdatEntry &Entry : C.second) {
1003 encodeULEB128(Entry.Kind, W.OS);
1004 encodeULEB128(Entry.Index, W.OS);
1005 }
1006 }
1007 endSection(SubSection);
1008 }
1009
1010 endSection(Section);
1011 }
1012
writeCustomSection(WasmCustomSection & CustomSection,const MCAssembler & Asm,const MCAsmLayout & Layout)1013 void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection,
1014 const MCAssembler &Asm,
1015 const MCAsmLayout &Layout) {
1016 SectionBookkeeping Section;
1017 auto *Sec = CustomSection.Section;
1018 startCustomSection(Section, CustomSection.Name);
1019
1020 Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
1021 Asm.writeSectionData(W.OS, Sec, Layout);
1022
1023 CustomSection.OutputContentsOffset = Section.ContentsOffset;
1024 CustomSection.OutputIndex = Section.Index;
1025
1026 endSection(Section);
1027
1028 // Apply fixups.
1029 auto &Relocations = CustomSectionsRelocations[CustomSection.Section];
1030 applyRelocations(Relocations, CustomSection.OutputContentsOffset);
1031 }
1032
getFunctionType(const MCSymbolWasm & Symbol)1033 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
1034 assert(Symbol.isFunction());
1035 assert(TypeIndices.count(&Symbol));
1036 return TypeIndices[&Symbol];
1037 }
1038
getEventType(const MCSymbolWasm & Symbol)1039 uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) {
1040 assert(Symbol.isEvent());
1041 assert(TypeIndices.count(&Symbol));
1042 return TypeIndices[&Symbol];
1043 }
1044
registerFunctionType(const MCSymbolWasm & Symbol)1045 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
1046 assert(Symbol.isFunction());
1047
1048 WasmSignature S;
1049 const MCSymbolWasm *ResolvedSym = resolveSymbol(Symbol);
1050 if (auto *Sig = ResolvedSym->getSignature()) {
1051 S.Returns = Sig->Returns;
1052 S.Params = Sig->Params;
1053 }
1054
1055 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
1056 if (Pair.second)
1057 Signatures.push_back(S);
1058 TypeIndices[&Symbol] = Pair.first->second;
1059
1060 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1061 << " new:" << Pair.second << "\n");
1062 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
1063 }
1064
registerEventType(const MCSymbolWasm & Symbol)1065 void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) {
1066 assert(Symbol.isEvent());
1067
1068 // TODO Currently we don't generate imported exceptions, but if we do, we
1069 // should have a way of infering types of imported exceptions.
1070 WasmSignature S;
1071 if (auto *Sig = Symbol.getSignature()) {
1072 S.Returns = Sig->Returns;
1073 S.Params = Sig->Params;
1074 }
1075
1076 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
1077 if (Pair.second)
1078 Signatures.push_back(S);
1079 TypeIndices[&Symbol] = Pair.first->second;
1080
1081 LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second
1082 << "\n");
1083 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
1084 }
1085
isInSymtab(const MCSymbolWasm & Sym)1086 static bool isInSymtab(const MCSymbolWasm &Sym) {
1087 if (Sym.isUsedInReloc())
1088 return true;
1089
1090 if (Sym.isComdat() && !Sym.isDefined())
1091 return false;
1092
1093 if (Sym.isTemporary() && Sym.getName().empty())
1094 return false;
1095
1096 if (Sym.isTemporary() && Sym.isData() && !Sym.getSize())
1097 return false;
1098
1099 if (Sym.isSection())
1100 return false;
1101
1102 return true;
1103 }
1104
writeObject(MCAssembler & Asm,const MCAsmLayout & Layout)1105 uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
1106 const MCAsmLayout &Layout) {
1107 uint64_t StartOffset = W.OS.tell();
1108
1109 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1110
1111 // Collect information from the available symbols.
1112 SmallVector<WasmFunction, 4> Functions;
1113 SmallVector<uint32_t, 4> TableElems;
1114 SmallVector<wasm::WasmImport, 4> Imports;
1115 SmallVector<wasm::WasmExport, 4> Exports;
1116 SmallVector<wasm::WasmEventType, 1> Events;
1117 SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
1118 SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
1119 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
1120 uint32_t DataSize = 0;
1121
1122 // For now, always emit the memory import, since loads and stores are not
1123 // valid without it. In the future, we could perhaps be more clever and omit
1124 // it if there are no loads or stores.
1125 wasm::WasmImport MemImport;
1126 MemImport.Module = "env";
1127 MemImport.Field = "__linear_memory";
1128 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
1129 Imports.push_back(MemImport);
1130
1131 // For now, always emit the table section, since indirect calls are not
1132 // valid without it. In the future, we could perhaps be more clever and omit
1133 // it if there are no indirect calls.
1134 wasm::WasmImport TableImport;
1135 TableImport.Module = "env";
1136 TableImport.Field = "__indirect_function_table";
1137 TableImport.Kind = wasm::WASM_EXTERNAL_TABLE;
1138 TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF;
1139 Imports.push_back(TableImport);
1140
1141 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1142 // symbols. This must be done before populating WasmIndices for defined
1143 // symbols.
1144 for (const MCSymbol &S : Asm.symbols()) {
1145 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1146
1147 // Register types for all functions, including those with private linkage
1148 // (because wasm always needs a type signature).
1149 if (WS.isFunction())
1150 registerFunctionType(WS);
1151
1152 if (WS.isEvent())
1153 registerEventType(WS);
1154
1155 if (WS.isTemporary())
1156 continue;
1157
1158 // If the symbol is not defined in this translation unit, import it.
1159 if (!WS.isDefined() && !WS.isComdat()) {
1160 if (WS.isFunction()) {
1161 wasm::WasmImport Import;
1162 Import.Module = WS.getImportModule();
1163 Import.Field = WS.getImportName();
1164 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1165 Import.SigIndex = getFunctionType(WS);
1166 Imports.push_back(Import);
1167 assert(WasmIndices.count(&WS) == 0);
1168 WasmIndices[&WS] = NumFunctionImports++;
1169 } else if (WS.isGlobal()) {
1170 if (WS.isWeak())
1171 report_fatal_error("undefined global symbol cannot be weak");
1172
1173 wasm::WasmImport Import;
1174 Import.Field = WS.getImportName();
1175 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1176 Import.Module = WS.getImportModule();
1177 Import.Global = WS.getGlobalType();
1178 Imports.push_back(Import);
1179 assert(WasmIndices.count(&WS) == 0);
1180 WasmIndices[&WS] = NumGlobalImports++;
1181 } else if (WS.isEvent()) {
1182 if (WS.isWeak())
1183 report_fatal_error("undefined event symbol cannot be weak");
1184
1185 wasm::WasmImport Import;
1186 Import.Module = WS.getImportModule();
1187 Import.Field = WS.getImportName();
1188 Import.Kind = wasm::WASM_EXTERNAL_EVENT;
1189 Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
1190 Import.Event.SigIndex = getEventType(WS);
1191 Imports.push_back(Import);
1192 assert(WasmIndices.count(&WS) == 0);
1193 WasmIndices[&WS] = NumEventImports++;
1194 }
1195 }
1196 }
1197
1198 // Add imports for GOT globals
1199 for (const MCSymbol &S : Asm.symbols()) {
1200 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1201 if (WS.isUsedInGOT()) {
1202 wasm::WasmImport Import;
1203 if (WS.isFunction())
1204 Import.Module = "GOT.func";
1205 else
1206 Import.Module = "GOT.mem";
1207 Import.Field = WS.getName();
1208 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1209 Import.Global = {wasm::WASM_TYPE_I32, true};
1210 Imports.push_back(Import);
1211 assert(GOTIndices.count(&WS) == 0);
1212 GOTIndices[&WS] = NumGlobalImports++;
1213 }
1214 }
1215
1216 // Populate DataSegments and CustomSections, which must be done before
1217 // populating DataLocations.
1218 for (MCSection &Sec : Asm) {
1219 auto &Section = static_cast<MCSectionWasm &>(Sec);
1220 StringRef SectionName = Section.getSectionName();
1221
1222 // .init_array sections are handled specially elsewhere.
1223 if (SectionName.startswith(".init_array"))
1224 continue;
1225
1226 // Code is handled separately
1227 if (Section.getKind().isText())
1228 continue;
1229
1230 if (Section.isWasmData()) {
1231 uint32_t SegmentIndex = DataSegments.size();
1232 DataSize = alignTo(DataSize, Section.getAlignment());
1233 DataSegments.emplace_back();
1234 WasmDataSegment &Segment = DataSegments.back();
1235 Segment.Name = SectionName;
1236 Segment.InitFlags =
1237 Section.getPassive() ? (uint32_t)wasm::WASM_SEGMENT_IS_PASSIVE : 0;
1238 Segment.Offset = DataSize;
1239 Segment.Section = &Section;
1240 addData(Segment.Data, Section);
1241 Segment.Alignment = Log2_32(Section.getAlignment());
1242 Segment.LinkerFlags = 0;
1243 DataSize += Segment.Data.size();
1244 Section.setSegmentIndex(SegmentIndex);
1245
1246 if (const MCSymbolWasm *C = Section.getGroup()) {
1247 Comdats[C->getName()].emplace_back(
1248 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
1249 }
1250 } else {
1251 // Create custom sections
1252 assert(Sec.getKind().isMetadata());
1253
1254 StringRef Name = SectionName;
1255
1256 // For user-defined custom sections, strip the prefix
1257 if (Name.startswith(".custom_section."))
1258 Name = Name.substr(strlen(".custom_section."));
1259
1260 MCSymbol *Begin = Sec.getBeginSymbol();
1261 if (Begin) {
1262 WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size();
1263 if (SectionName != Begin->getName())
1264 report_fatal_error("section name and begin symbol should match: " +
1265 Twine(SectionName));
1266 }
1267
1268 // Separate out the producers and target features sections
1269 if (Name == "producers") {
1270 ProducersSection = std::make_unique<WasmCustomSection>(Name, &Section);
1271 continue;
1272 }
1273 if (Name == "target_features") {
1274 TargetFeaturesSection =
1275 std::make_unique<WasmCustomSection>(Name, &Section);
1276 continue;
1277 }
1278
1279 CustomSections.emplace_back(Name, &Section);
1280 }
1281 }
1282
1283 // Populate WasmIndices and DataLocations for defined symbols.
1284 for (const MCSymbol &S : Asm.symbols()) {
1285 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1286 // or used in relocations.
1287 if (S.isTemporary() && S.getName().empty())
1288 continue;
1289
1290 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1291 LLVM_DEBUG(
1292 dbgs() << "MCSymbol: " << toString(WS.getType()) << " '" << S << "'"
1293 << " isDefined=" << S.isDefined() << " isExternal="
1294 << S.isExternal() << " isTemporary=" << S.isTemporary()
1295 << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden()
1296 << " isVariable=" << WS.isVariable() << "\n");
1297
1298 if (WS.isVariable())
1299 continue;
1300 if (WS.isComdat() && !WS.isDefined())
1301 continue;
1302
1303 if (WS.isFunction()) {
1304 unsigned Index;
1305 if (WS.isDefined()) {
1306 if (WS.getOffset() != 0)
1307 report_fatal_error(
1308 "function sections must contain one function each");
1309
1310 if (WS.getSize() == nullptr)
1311 report_fatal_error(
1312 "function symbols must have a size set with .size");
1313
1314 // A definition. Write out the function body.
1315 Index = NumFunctionImports + Functions.size();
1316 WasmFunction Func;
1317 Func.SigIndex = getFunctionType(WS);
1318 Func.Sym = &WS;
1319 WasmIndices[&WS] = Index;
1320 Functions.push_back(Func);
1321
1322 auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
1323 if (const MCSymbolWasm *C = Section.getGroup()) {
1324 Comdats[C->getName()].emplace_back(
1325 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
1326 }
1327
1328 if (WS.hasExportName()) {
1329 wasm::WasmExport Export;
1330 Export.Name = WS.getExportName();
1331 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1332 Export.Index = Index;
1333 Exports.push_back(Export);
1334 }
1335 } else {
1336 // An import; the index was assigned above.
1337 Index = WasmIndices.find(&WS)->second;
1338 }
1339
1340 LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
1341
1342 } else if (WS.isData()) {
1343 if (!isInSymtab(WS))
1344 continue;
1345
1346 if (!WS.isDefined()) {
1347 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1348 << "\n");
1349 continue;
1350 }
1351
1352 if (!WS.getSize())
1353 report_fatal_error("data symbols must have a size set with .size: " +
1354 WS.getName());
1355
1356 int64_t Size = 0;
1357 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
1358 report_fatal_error(".size expression must be evaluatable");
1359
1360 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
1361 if (!DataSection.isWasmData())
1362 report_fatal_error("data symbols must live in a data section: " +
1363 WS.getName());
1364
1365 // For each data symbol, export it in the symtab as a reference to the
1366 // corresponding Wasm data segment.
1367 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1368 DataSection.getSegmentIndex(),
1369 static_cast<uint32_t>(Layout.getSymbolOffset(WS)),
1370 static_cast<uint32_t>(Size)};
1371 DataLocations[&WS] = Ref;
1372 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
1373
1374 } else if (WS.isGlobal()) {
1375 // A "true" Wasm global (currently just __stack_pointer)
1376 if (WS.isDefined())
1377 report_fatal_error("don't yet support defined globals");
1378
1379 // An import; the index was assigned above
1380 LLVM_DEBUG(dbgs() << " -> global index: "
1381 << WasmIndices.find(&WS)->second << "\n");
1382
1383 } else if (WS.isEvent()) {
1384 // C++ exception symbol (__cpp_exception)
1385 unsigned Index;
1386 if (WS.isDefined()) {
1387 Index = NumEventImports + Events.size();
1388 wasm::WasmEventType Event;
1389 Event.SigIndex = getEventType(WS);
1390 Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
1391 assert(WasmIndices.count(&WS) == 0);
1392 WasmIndices[&WS] = Index;
1393 Events.push_back(Event);
1394 } else {
1395 // An import; the index was assigned above.
1396 assert(WasmIndices.count(&WS) > 0);
1397 }
1398 LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second
1399 << "\n");
1400
1401 } else {
1402 assert(WS.isSection());
1403 }
1404 }
1405
1406 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1407 // process these in a separate pass because we need to have processed the
1408 // target of the alias before the alias itself and the symbols are not
1409 // necessarily ordered in this way.
1410 for (const MCSymbol &S : Asm.symbols()) {
1411 if (!S.isVariable())
1412 continue;
1413
1414 assert(S.isDefined());
1415
1416 // Find the target symbol of this weak alias and export that index
1417 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1418 const MCSymbolWasm *ResolvedSym = resolveSymbol(WS);
1419 LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym
1420 << "'\n");
1421
1422 if (ResolvedSym->isFunction()) {
1423 assert(WasmIndices.count(ResolvedSym) > 0);
1424 uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
1425 assert(WasmIndices.count(&WS) == 0);
1426 WasmIndices[&WS] = WasmIndex;
1427 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
1428 } else if (ResolvedSym->isData()) {
1429 assert(DataLocations.count(ResolvedSym) > 0);
1430 const wasm::WasmDataReference &Ref =
1431 DataLocations.find(ResolvedSym)->second;
1432 DataLocations[&WS] = Ref;
1433 LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
1434 } else {
1435 report_fatal_error("don't yet support global/event aliases");
1436 }
1437 }
1438
1439 // Finally, populate the symbol table itself, in its "natural" order.
1440 for (const MCSymbol &S : Asm.symbols()) {
1441 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1442 if (!isInSymtab(WS)) {
1443 WS.setIndex(InvalidIndex);
1444 continue;
1445 }
1446 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
1447
1448 uint32_t Flags = 0;
1449 if (WS.isWeak())
1450 Flags |= wasm::WASM_SYMBOL_BINDING_WEAK;
1451 if (WS.isHidden())
1452 Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
1453 if (!WS.isExternal() && WS.isDefined())
1454 Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
1455 if (WS.isUndefined())
1456 Flags |= wasm::WASM_SYMBOL_UNDEFINED;
1457 if (WS.isNoStrip()) {
1458 Flags |= wasm::WASM_SYMBOL_NO_STRIP;
1459 if (isEmscripten()) {
1460 Flags |= wasm::WASM_SYMBOL_EXPORTED;
1461 }
1462 }
1463 if (WS.hasImportName())
1464 Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
1465 if (WS.hasExportName())
1466 Flags |= wasm::WASM_SYMBOL_EXPORTED;
1467
1468 wasm::WasmSymbolInfo Info;
1469 Info.Name = WS.getName();
1470 Info.Kind = WS.getType();
1471 Info.Flags = Flags;
1472 if (!WS.isData()) {
1473 assert(WasmIndices.count(&WS) > 0);
1474 Info.ElementIndex = WasmIndices.find(&WS)->second;
1475 } else if (WS.isDefined()) {
1476 assert(DataLocations.count(&WS) > 0);
1477 Info.DataRef = DataLocations.find(&WS)->second;
1478 }
1479 WS.setIndex(SymbolInfos.size());
1480 SymbolInfos.emplace_back(Info);
1481 }
1482
1483 {
1484 auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
1485 // Functions referenced by a relocation need to put in the table. This is
1486 // purely to make the object file's provisional values readable, and is
1487 // ignored by the linker, which re-calculates the relocations itself.
1488 if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
1489 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB)
1490 return;
1491 assert(Rel.Symbol->isFunction());
1492 const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol);
1493 uint32_t FunctionIndex = WasmIndices.find(&WS)->second;
1494 uint32_t TableIndex = TableElems.size() + InitialTableOffset;
1495 if (TableIndices.try_emplace(&WS, TableIndex).second) {
1496 LLVM_DEBUG(dbgs() << " -> adding " << WS.getName()
1497 << " to table: " << TableIndex << "\n");
1498 TableElems.push_back(FunctionIndex);
1499 registerFunctionType(WS);
1500 }
1501 };
1502
1503 for (const WasmRelocationEntry &RelEntry : CodeRelocations)
1504 HandleReloc(RelEntry);
1505 for (const WasmRelocationEntry &RelEntry : DataRelocations)
1506 HandleReloc(RelEntry);
1507 }
1508
1509 // Translate .init_array section contents into start functions.
1510 for (const MCSection &S : Asm) {
1511 const auto &WS = static_cast<const MCSectionWasm &>(S);
1512 if (WS.getSectionName().startswith(".fini_array"))
1513 report_fatal_error(".fini_array sections are unsupported");
1514 if (!WS.getSectionName().startswith(".init_array"))
1515 continue;
1516 if (WS.getFragmentList().empty())
1517 continue;
1518
1519 // init_array is expected to contain a single non-empty data fragment
1520 if (WS.getFragmentList().size() != 3)
1521 report_fatal_error("only one .init_array section fragment supported");
1522
1523 auto IT = WS.begin();
1524 const MCFragment &EmptyFrag = *IT;
1525 if (EmptyFrag.getKind() != MCFragment::FT_Data)
1526 report_fatal_error(".init_array section should be aligned");
1527
1528 IT = std::next(IT);
1529 const MCFragment &AlignFrag = *IT;
1530 if (AlignFrag.getKind() != MCFragment::FT_Align)
1531 report_fatal_error(".init_array section should be aligned");
1532 if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4))
1533 report_fatal_error(".init_array section should be aligned for pointers");
1534
1535 const MCFragment &Frag = *std::next(IT);
1536 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1537 report_fatal_error("only data supported in .init_array section");
1538
1539 uint16_t Priority = UINT16_MAX;
1540 unsigned PrefixLength = strlen(".init_array");
1541 if (WS.getSectionName().size() > PrefixLength) {
1542 if (WS.getSectionName()[PrefixLength] != '.')
1543 report_fatal_error(
1544 ".init_array section priority should start with '.'");
1545 if (WS.getSectionName()
1546 .substr(PrefixLength + 1)
1547 .getAsInteger(10, Priority))
1548 report_fatal_error("invalid .init_array section priority");
1549 }
1550 const auto &DataFrag = cast<MCDataFragment>(Frag);
1551 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1552 for (const uint8_t *
1553 P = (const uint8_t *)Contents.data(),
1554 *End = (const uint8_t *)Contents.data() + Contents.size();
1555 P != End; ++P) {
1556 if (*P != 0)
1557 report_fatal_error("non-symbolic data in .init_array section");
1558 }
1559 for (const MCFixup &Fixup : DataFrag.getFixups()) {
1560 assert(Fixup.getKind() ==
1561 MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1562 const MCExpr *Expr = Fixup.getValue();
1563 auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr);
1564 if (!SymRef)
1565 report_fatal_error("fixups in .init_array should be symbol references");
1566 const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol());
1567 if (TargetSym.getIndex() == InvalidIndex)
1568 report_fatal_error("symbols in .init_array should exist in symbtab");
1569 if (!TargetSym.isFunction())
1570 report_fatal_error("symbols in .init_array should be for functions");
1571 InitFuncs.push_back(
1572 std::make_pair(Priority, TargetSym.getIndex()));
1573 }
1574 }
1575
1576 // Write out the Wasm header.
1577 writeHeader(Asm);
1578
1579 writeTypeSection(Signatures);
1580 writeImportSection(Imports, DataSize, TableElems.size());
1581 writeFunctionSection(Functions);
1582 // Skip the "table" section; we import the table instead.
1583 // Skip the "memory" section; we import the memory instead.
1584 writeEventSection(Events);
1585 writeExportSection(Exports);
1586 writeElemSection(TableElems);
1587 writeDataCountSection();
1588 writeCodeSection(Asm, Layout, Functions);
1589 writeDataSection();
1590 for (auto &CustomSection : CustomSections)
1591 writeCustomSection(CustomSection, Asm, Layout);
1592 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
1593 writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
1594 writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
1595 writeCustomRelocSections();
1596 if (ProducersSection)
1597 writeCustomSection(*ProducersSection, Asm, Layout);
1598 if (TargetFeaturesSection)
1599 writeCustomSection(*TargetFeaturesSection, Asm, Layout);
1600
1601 // TODO: Translate the .comment section to the output.
1602 return W.OS.tell() - StartOffset;
1603 }
1604
1605 std::unique_ptr<MCObjectWriter>
createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,raw_pwrite_stream & OS)1606 llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1607 raw_pwrite_stream &OS) {
1608 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
1609 }
1610