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/BinaryFormat/Wasm.h"
15 #include "llvm/BinaryFormat/WasmTraits.h"
16 #include "llvm/Config/llvm-config.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAssembler.h"
19 #include "llvm/MC/MCContext.h"
20 #include "llvm/MC/MCExpr.h"
21 #include "llvm/MC/MCObjectWriter.h"
22 #include "llvm/MC/MCSectionWasm.h"
23 #include "llvm/MC/MCSymbolWasm.h"
24 #include "llvm/MC/MCValue.h"
25 #include "llvm/MC/MCWasmObjectWriter.h"
26 #include "llvm/Support/Casting.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/EndianStream.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/LEB128.h"
31 #include <vector>
32
33 using namespace llvm;
34
35 #define DEBUG_TYPE "mc"
36
37 namespace {
38
39 // When we create the indirect function table we start at 1, so that there is
40 // and empty slot at 0 and therefore calling a null function pointer will trap.
41 static const uint32_t InitialTableOffset = 1;
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 section header ends (without custom section name).
50 uint64_t PayloadOffset;
51 // Where the contents of the section starts.
52 uint64_t ContentsOffset;
53 uint32_t Index;
54 };
55
56 // A wasm data segment. A wasm binary contains only a single data section
57 // but that can contain many segments, each with their own virtual location
58 // in memory. Each MCSection data created by llvm is modeled as its own
59 // wasm data segment.
60 struct WasmDataSegment {
61 MCSectionWasm *Section;
62 StringRef Name;
63 uint32_t InitFlags;
64 uint64_t Offset;
65 uint32_t Alignment;
66 uint32_t LinkingFlags;
67 SmallVector<char, 4> Data;
68 };
69
70 // A wasm function to be written into the function section.
71 struct WasmFunction {
72 uint32_t SigIndex;
73 MCSection *Section;
74 };
75
76 // A wasm global to be written into the global section.
77 struct WasmGlobal {
78 wasm::WasmGlobalType Type;
79 uint64_t InitialValue;
80 };
81
82 // Information about a single item which is part of a COMDAT. For each data
83 // segment or function which is in the COMDAT, there is a corresponding
84 // WasmComdatEntry.
85 struct WasmComdatEntry {
86 unsigned Kind;
87 uint32_t Index;
88 };
89
90 // Information about a single relocation.
91 struct WasmRelocationEntry {
92 uint64_t Offset; // Where is the relocation.
93 const MCSymbolWasm *Symbol; // The symbol to relocate with.
94 int64_t Addend; // A value to add to the symbol.
95 unsigned Type; // The type of the relocation.
96 const MCSectionWasm *FixupSection; // The section the relocation is targeting.
97
WasmRelocationEntry__anon335a907b0111::WasmRelocationEntry98 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
99 int64_t Addend, unsigned Type,
100 const MCSectionWasm *FixupSection)
101 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
102 FixupSection(FixupSection) {}
103
hasAddend__anon335a907b0111::WasmRelocationEntry104 bool hasAddend() const { return wasm::relocTypeHasAddend(Type); }
105
print__anon335a907b0111::WasmRelocationEntry106 void print(raw_ostream &Out) const {
107 Out << wasm::relocTypetoString(Type) << " Off=" << Offset
108 << ", Sym=" << *Symbol << ", Addend=" << Addend
109 << ", FixupSection=" << FixupSection->getName();
110 }
111
112 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump__anon335a907b0111::WasmRelocationEntry113 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
114 #endif
115 };
116
117 static const uint32_t InvalidIndex = -1;
118
119 struct WasmCustomSection {
120
121 StringRef Name;
122 MCSectionWasm *Section;
123
124 uint32_t OutputContentsOffset = 0;
125 uint32_t OutputIndex = InvalidIndex;
126
WasmCustomSection__anon335a907b0111::WasmCustomSection127 WasmCustomSection(StringRef Name, MCSectionWasm *Section)
128 : Name(Name), Section(Section) {}
129 };
130
131 #if !defined(NDEBUG)
operator <<(raw_ostream & OS,const WasmRelocationEntry & Rel)132 raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
133 Rel.print(OS);
134 return OS;
135 }
136 #endif
137
138 // Write Value as an (unsigned) LEB value at offset Offset in Stream, padded
139 // to allow patching.
140 template <typename T, int W>
writePatchableULEB(raw_pwrite_stream & Stream,T Value,uint64_t Offset)141 void writePatchableULEB(raw_pwrite_stream &Stream, T Value, uint64_t Offset) {
142 uint8_t Buffer[W];
143 unsigned SizeLen = encodeULEB128(Value, Buffer, W);
144 assert(SizeLen == W);
145 Stream.pwrite((char *)Buffer, SizeLen, Offset);
146 }
147
148 // Write Value as an signed LEB value at offset Offset in Stream, padded
149 // to allow patching.
150 template <typename T, int W>
writePatchableSLEB(raw_pwrite_stream & Stream,T Value,uint64_t Offset)151 void writePatchableSLEB(raw_pwrite_stream &Stream, T Value, uint64_t Offset) {
152 uint8_t Buffer[W];
153 unsigned SizeLen = encodeSLEB128(Value, Buffer, W);
154 assert(SizeLen == W);
155 Stream.pwrite((char *)Buffer, SizeLen, Offset);
156 }
157
writePatchableU32(raw_pwrite_stream & Stream,uint32_t Value,uint64_t Offset)158 static void writePatchableU32(raw_pwrite_stream &Stream, uint32_t Value,
159 uint64_t Offset) {
160 writePatchableULEB<uint32_t, 5>(Stream, Value, Offset);
161 }
162
writePatchableS32(raw_pwrite_stream & Stream,int32_t Value,uint64_t Offset)163 static void writePatchableS32(raw_pwrite_stream &Stream, int32_t Value,
164 uint64_t Offset) {
165 writePatchableSLEB<int32_t, 5>(Stream, Value, Offset);
166 }
167
writePatchableU64(raw_pwrite_stream & Stream,uint64_t Value,uint64_t Offset)168 static void writePatchableU64(raw_pwrite_stream &Stream, uint64_t Value,
169 uint64_t Offset) {
170 writePatchableSLEB<uint64_t, 10>(Stream, Value, Offset);
171 }
172
writePatchableS64(raw_pwrite_stream & Stream,int64_t Value,uint64_t Offset)173 static void writePatchableS64(raw_pwrite_stream &Stream, int64_t Value,
174 uint64_t Offset) {
175 writePatchableSLEB<int64_t, 10>(Stream, Value, Offset);
176 }
177
178 // Write Value as a plain integer value at offset Offset in Stream.
patchI32(raw_pwrite_stream & Stream,uint32_t Value,uint64_t Offset)179 static void patchI32(raw_pwrite_stream &Stream, uint32_t Value,
180 uint64_t Offset) {
181 uint8_t Buffer[4];
182 support::endian::write32le(Buffer, Value);
183 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
184 }
185
patchI64(raw_pwrite_stream & Stream,uint64_t Value,uint64_t Offset)186 static void patchI64(raw_pwrite_stream &Stream, uint64_t Value,
187 uint64_t Offset) {
188 uint8_t Buffer[8];
189 support::endian::write64le(Buffer, Value);
190 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
191 }
192
isDwoSection(const MCSection & Sec)193 bool isDwoSection(const MCSection &Sec) {
194 return Sec.getName().ends_with(".dwo");
195 }
196
197 class WasmObjectWriter : public MCObjectWriter {
198 support::endian::Writer *W = nullptr;
199
200 /// The target specific Wasm writer instance.
201 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
202
203 // Relocations for fixing up references in the code section.
204 std::vector<WasmRelocationEntry> CodeRelocations;
205 // Relocations for fixing up references in the data section.
206 std::vector<WasmRelocationEntry> DataRelocations;
207
208 // Index values to use for fixing up call_indirect type indices.
209 // Maps function symbols to the index of the type of the function
210 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
211 // Maps function symbols to the table element index space. Used
212 // for TABLE_INDEX relocation types (i.e. address taken functions).
213 DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
214 // Maps function/global/table symbols to the
215 // function/global/table/tag/section index space.
216 DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
217 DenseMap<const MCSymbolWasm *, uint32_t> GOTIndices;
218 // Maps data symbols to the Wasm segment and offset/size with the segment.
219 DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
220
221 // Stores output data (index, relocations, content offset) for custom
222 // section.
223 std::vector<WasmCustomSection> CustomSections;
224 std::unique_ptr<WasmCustomSection> ProducersSection;
225 std::unique_ptr<WasmCustomSection> TargetFeaturesSection;
226 // Relocations for fixing up references in the custom sections.
227 DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
228 CustomSectionsRelocations;
229
230 // Map from section to defining function symbol.
231 DenseMap<const MCSection *, const MCSymbol *> SectionFunctions;
232
233 DenseMap<wasm::WasmSignature, uint32_t> SignatureIndices;
234 SmallVector<wasm::WasmSignature, 4> Signatures;
235 SmallVector<WasmDataSegment, 4> DataSegments;
236 unsigned NumFunctionImports = 0;
237 unsigned NumGlobalImports = 0;
238 unsigned NumTableImports = 0;
239 unsigned NumTagImports = 0;
240 uint32_t SectionCount = 0;
241
242 enum class DwoMode {
243 AllSections,
244 NonDwoOnly,
245 DwoOnly,
246 };
247 bool IsSplitDwarf = false;
248 raw_pwrite_stream *OS = nullptr;
249 raw_pwrite_stream *DwoOS = nullptr;
250
251 // TargetObjectWriter wranppers.
is64Bit() const252 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
isEmscripten() const253 bool isEmscripten() const { return TargetObjectWriter->isEmscripten(); }
254
255 void startSection(SectionBookkeeping &Section, unsigned SectionId);
256 void startCustomSection(SectionBookkeeping &Section, StringRef Name);
257 void endSection(SectionBookkeeping &Section);
258
259 public:
WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,raw_pwrite_stream & OS_)260 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
261 raw_pwrite_stream &OS_)
262 : TargetObjectWriter(std::move(MOTW)), OS(&OS_) {}
263
WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,raw_pwrite_stream & OS_,raw_pwrite_stream & DwoOS_)264 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
265 raw_pwrite_stream &OS_, raw_pwrite_stream &DwoOS_)
266 : TargetObjectWriter(std::move(MOTW)), IsSplitDwarf(true), OS(&OS_),
267 DwoOS(&DwoOS_) {}
268
269 private:
reset()270 void reset() override {
271 CodeRelocations.clear();
272 DataRelocations.clear();
273 TypeIndices.clear();
274 WasmIndices.clear();
275 GOTIndices.clear();
276 TableIndices.clear();
277 DataLocations.clear();
278 CustomSections.clear();
279 ProducersSection.reset();
280 TargetFeaturesSection.reset();
281 CustomSectionsRelocations.clear();
282 SignatureIndices.clear();
283 Signatures.clear();
284 DataSegments.clear();
285 SectionFunctions.clear();
286 NumFunctionImports = 0;
287 NumGlobalImports = 0;
288 NumTableImports = 0;
289 MCObjectWriter::reset();
290 }
291
292 void writeHeader(const MCAssembler &Asm);
293
294 void recordRelocation(const MCFragment &F, const MCFixup &Fixup,
295 MCValue Target, uint64_t &FixedValue) override;
296
297 void executePostLayoutBinding() override;
298 void prepareImports(SmallVectorImpl<wasm::WasmImport> &Imports,
299 MCAssembler &Asm);
300 uint64_t writeObject() override;
301
302 uint64_t writeOneObject(MCAssembler &Asm, DwoMode Mode);
303
writeString(const StringRef Str)304 void writeString(const StringRef Str) {
305 encodeULEB128(Str.size(), W->OS);
306 W->OS << Str;
307 }
308
309 void writeStringWithAlignment(const StringRef Str, unsigned Alignment);
310
writeI32(int32_t val)311 void writeI32(int32_t val) {
312 char Buffer[4];
313 support::endian::write32le(Buffer, val);
314 W->OS.write(Buffer, sizeof(Buffer));
315 }
316
writeI64(int64_t val)317 void writeI64(int64_t val) {
318 char Buffer[8];
319 support::endian::write64le(Buffer, val);
320 W->OS.write(Buffer, sizeof(Buffer));
321 }
322
writeValueType(wasm::ValType Ty)323 void writeValueType(wasm::ValType Ty) { W->OS << static_cast<char>(Ty); }
324
325 void writeTypeSection(ArrayRef<wasm::WasmSignature> Signatures);
326 void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint64_t DataSize,
327 uint32_t NumElements);
328 void writeFunctionSection(ArrayRef<WasmFunction> Functions);
329 void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
330 void writeElemSection(const MCSymbolWasm *IndirectFunctionTable,
331 ArrayRef<uint32_t> TableElems);
332 void writeDataCountSection();
333 uint32_t writeCodeSection(const MCAssembler &Asm,
334 ArrayRef<WasmFunction> Functions);
335 uint32_t writeDataSection(const MCAssembler &Asm);
336 void writeTagSection(ArrayRef<uint32_t> TagTypes);
337 void writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals);
338 void writeTableSection(ArrayRef<wasm::WasmTable> Tables);
339 void writeRelocSection(uint32_t SectionIndex, StringRef Name,
340 std::vector<WasmRelocationEntry> &Relocations);
341 void writeLinkingMetaDataSection(
342 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
343 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
344 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
345 void writeCustomSection(WasmCustomSection &CustomSection,
346 const MCAssembler &Asm);
347 void writeCustomRelocSections();
348
349 uint64_t getProvisionalValue(const MCAssembler &Asm,
350 const WasmRelocationEntry &RelEntry);
351 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
352 uint64_t ContentsOffset, const MCAssembler &Asm);
353
354 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
355 uint32_t getFunctionType(const MCSymbolWasm &Symbol);
356 uint32_t getTagType(const MCSymbolWasm &Symbol);
357 void registerFunctionType(const MCSymbolWasm &Symbol);
358 void registerTagType(const MCSymbolWasm &Symbol);
359 };
360
361 } // end anonymous namespace
362
363 // Write out a section header and a patchable section size field.
startSection(SectionBookkeeping & Section,unsigned SectionId)364 void WasmObjectWriter::startSection(SectionBookkeeping &Section,
365 unsigned SectionId) {
366 LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n");
367 W->OS << char(SectionId);
368
369 Section.SizeOffset = W->OS.tell();
370
371 // The section size. We don't know the size yet, so reserve enough space
372 // for any 32-bit value; we'll patch it later.
373 encodeULEB128(0, W->OS, 5);
374
375 // The position where the section starts, for measuring its size.
376 Section.ContentsOffset = W->OS.tell();
377 Section.PayloadOffset = W->OS.tell();
378 Section.Index = SectionCount++;
379 }
380
381 // Write a string with extra paddings for trailing alignment
382 // TODO: support alignment at asm and llvm level?
writeStringWithAlignment(const StringRef Str,unsigned Alignment)383 void WasmObjectWriter::writeStringWithAlignment(const StringRef Str,
384 unsigned Alignment) {
385
386 // Calculate the encoded size of str length and add pads based on it and
387 // alignment.
388 raw_null_ostream NullOS;
389 uint64_t StrSizeLength = encodeULEB128(Str.size(), NullOS);
390 uint64_t Offset = W->OS.tell() + StrSizeLength + Str.size();
391 uint64_t Paddings = offsetToAlignment(Offset, Align(Alignment));
392 Offset += Paddings;
393
394 // LEB128 greater than 5 bytes is invalid
395 assert((StrSizeLength + Paddings) <= 5 && "too long string to align");
396
397 encodeSLEB128(Str.size(), W->OS, StrSizeLength + Paddings);
398 W->OS << Str;
399
400 assert(W->OS.tell() == Offset && "invalid padding");
401 }
402
startCustomSection(SectionBookkeeping & Section,StringRef Name)403 void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
404 StringRef Name) {
405 LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n");
406 startSection(Section, wasm::WASM_SEC_CUSTOM);
407
408 // The position where the section header ends, for measuring its size.
409 Section.PayloadOffset = W->OS.tell();
410
411 // Custom sections in wasm also have a string identifier.
412 if (Name != "__clangast") {
413 writeString(Name);
414 } else {
415 // The on-disk hashtable in clangast needs to be aligned by 4 bytes.
416 writeStringWithAlignment(Name, 4);
417 }
418
419 // The position where the custom section starts.
420 Section.ContentsOffset = W->OS.tell();
421 }
422
423 // Now that the section is complete and we know how big it is, patch up the
424 // section size field at the start of the section.
endSection(SectionBookkeeping & Section)425 void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
426 uint64_t Size = W->OS.tell();
427 // /dev/null doesn't support seek/tell and can report offset of 0.
428 // Simply skip this patching in that case.
429 if (!Size)
430 return;
431
432 Size -= Section.PayloadOffset;
433 if (uint32_t(Size) != Size)
434 report_fatal_error("section size does not fit in a uint32_t");
435
436 LLVM_DEBUG(dbgs() << "endSection size=" << Size << "\n");
437
438 // Write the final section size to the payload_len field, which follows
439 // the section id byte.
440 writePatchableU32(static_cast<raw_pwrite_stream &>(W->OS), Size,
441 Section.SizeOffset);
442 }
443
444 // Emit the Wasm header.
writeHeader(const MCAssembler & Asm)445 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
446 W->OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
447 W->write<uint32_t>(wasm::WasmVersion);
448 }
449
executePostLayoutBinding()450 void WasmObjectWriter::executePostLayoutBinding() {
451 // Some compilation units require the indirect function table to be present
452 // but don't explicitly reference it. This is the case for call_indirect
453 // without the reference-types feature, and also function bitcasts in all
454 // cases. In those cases the __indirect_function_table has the
455 // WASM_SYMBOL_NO_STRIP attribute. Here we make sure this symbol makes it to
456 // the assembler, if needed.
457 if (auto *Sym = Asm->getContext().lookupSymbol("__indirect_function_table")) {
458 const auto *WasmSym = static_cast<const MCSymbolWasm *>(Sym);
459 if (WasmSym->isNoStrip())
460 Asm->registerSymbol(*Sym);
461 }
462
463 // Build a map of sections to the function that defines them, for use
464 // in recordRelocation.
465 for (const MCSymbol &S : Asm->symbols()) {
466 const auto &WS = static_cast<const MCSymbolWasm &>(S);
467 if (WS.isDefined() && WS.isFunction() && !WS.isVariable()) {
468 const auto &Sec = static_cast<const MCSectionWasm &>(S.getSection());
469 auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S));
470 if (!Pair.second)
471 report_fatal_error("section already has a defining function: " +
472 Sec.getName());
473 }
474 }
475 }
476
recordRelocation(const MCFragment & F,const MCFixup & Fixup,MCValue Target,uint64_t & FixedValue)477 void WasmObjectWriter::recordRelocation(const MCFragment &F,
478 const MCFixup &Fixup, MCValue Target,
479 uint64_t &FixedValue) {
480 // The WebAssembly backend should never generate FKF_IsPCRel fixups
481 assert(!Fixup.isPCRel());
482
483 const auto &FixupSection = cast<MCSectionWasm>(*F.getParent());
484 uint64_t C = Target.getConstant();
485 uint64_t FixupOffset = Asm->getFragmentOffset(F) + Fixup.getOffset();
486 MCContext &Ctx = getContext();
487 bool IsLocRel = false;
488
489 if (const auto *RefB = Target.getSubSym()) {
490 const auto &SymB = cast<MCSymbolWasm>(*RefB);
491
492 if (FixupSection.isText()) {
493 Ctx.reportError(Fixup.getLoc(),
494 Twine("symbol '") + SymB.getName() +
495 "' unsupported subtraction expression used in "
496 "relocation in code section.");
497 return;
498 }
499
500 if (SymB.isUndefined()) {
501 Ctx.reportError(Fixup.getLoc(),
502 Twine("symbol '") + SymB.getName() +
503 "' can not be undefined in a subtraction expression");
504 return;
505 }
506 const MCSection &SecB = SymB.getSection();
507 if (&SecB != &FixupSection) {
508 Ctx.reportError(Fixup.getLoc(),
509 Twine("symbol '") + SymB.getName() +
510 "' can not be placed in a different section");
511 return;
512 }
513 IsLocRel = true;
514 C += FixupOffset - Asm->getSymbolOffset(SymB);
515 }
516
517 // We either rejected the fixup or folded B into C at this point.
518 const auto *SymA = cast<MCSymbolWasm>(Target.getAddSym());
519
520 // The .init_array isn't translated as data, so don't do relocations in it.
521 if (FixupSection.getName().starts_with(".init_array")) {
522 SymA->setUsedInInitArray();
523 return;
524 }
525
526 // Put any constant offset in an addend. Offsets can be negative, and
527 // LLVM expects wrapping, in contrast to wasm's immediates which can't
528 // be negative and don't wrap.
529 FixedValue = 0;
530
531 unsigned Type =
532 TargetObjectWriter->getRelocType(Target, Fixup, FixupSection, IsLocRel);
533
534 // Absolute offset within a section or a function.
535 // Currently only supported for metadata sections.
536 // See: test/MC/WebAssembly/blockaddress.ll
537 if ((Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
538 Type == wasm::R_WASM_FUNCTION_OFFSET_I64 ||
539 Type == wasm::R_WASM_SECTION_OFFSET_I32) &&
540 SymA->isDefined()) {
541 // SymA can be a temp data symbol that represents a function (in which case
542 // it needs to be replaced by the section symbol), [XXX and it apparently
543 // later gets changed again to a func symbol?] or it can be a real
544 // function symbol, in which case it can be left as-is.
545
546 if (!FixupSection.isMetadata())
547 report_fatal_error("relocations for function or section offsets are "
548 "only supported in metadata sections");
549
550 const MCSymbol *SectionSymbol = nullptr;
551 const MCSection &SecA = SymA->getSection();
552 if (SecA.isText()) {
553 auto SecSymIt = SectionFunctions.find(&SecA);
554 if (SecSymIt == SectionFunctions.end())
555 report_fatal_error("section doesn\'t have defining symbol");
556 SectionSymbol = SecSymIt->second;
557 } else {
558 SectionSymbol = SecA.getBeginSymbol();
559 }
560 if (!SectionSymbol)
561 report_fatal_error("section symbol is required for relocation");
562
563 C += Asm->getSymbolOffset(*SymA);
564 SymA = cast<MCSymbolWasm>(SectionSymbol);
565 }
566
567 if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
568 Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB64 ||
569 Type == wasm::R_WASM_TABLE_INDEX_SLEB ||
570 Type == wasm::R_WASM_TABLE_INDEX_SLEB64 ||
571 Type == wasm::R_WASM_TABLE_INDEX_I32 ||
572 Type == wasm::R_WASM_TABLE_INDEX_I64) {
573 // TABLE_INDEX relocs implicitly use the default indirect function table.
574 // We require the function table to have already been defined.
575 auto TableName = "__indirect_function_table";
576 MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(TableName));
577 if (!Sym) {
578 report_fatal_error("missing indirect function table symbol");
579 } else {
580 if (!Sym->isFunctionTable())
581 report_fatal_error("__indirect_function_table symbol has wrong type");
582 // Ensure that __indirect_function_table reaches the output.
583 Sym->setNoStrip();
584 Asm->registerSymbol(*Sym);
585 }
586 }
587
588 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
589 // against a named symbol.
590 if (Type != wasm::R_WASM_TYPE_INDEX_LEB) {
591 if (SymA->getName().empty())
592 report_fatal_error("relocations against un-named temporaries are not yet "
593 "supported by wasm");
594
595 SymA->setUsedInReloc();
596 }
597
598 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
599 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
600
601 if (FixupSection.isWasmData()) {
602 DataRelocations.push_back(Rec);
603 } else if (FixupSection.isText()) {
604 CodeRelocations.push_back(Rec);
605 } else if (FixupSection.isMetadata()) {
606 CustomSectionsRelocations[&FixupSection].push_back(Rec);
607 } else {
608 llvm_unreachable("unexpected section type");
609 }
610 }
611
612 // Compute a value to write into the code at the location covered
613 // by RelEntry. This value isn't used by the static linker; it just serves
614 // to make the object format more readable and more likely to be directly
615 // useable.
616 uint64_t
getProvisionalValue(const MCAssembler & Asm,const WasmRelocationEntry & RelEntry)617 WasmObjectWriter::getProvisionalValue(const MCAssembler &Asm,
618 const WasmRelocationEntry &RelEntry) {
619 if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB ||
620 RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) &&
621 !RelEntry.Symbol->isGlobal()) {
622 assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space");
623 return GOTIndices[RelEntry.Symbol];
624 }
625
626 switch (RelEntry.Type) {
627 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
628 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
629 case wasm::R_WASM_TABLE_INDEX_SLEB:
630 case wasm::R_WASM_TABLE_INDEX_SLEB64:
631 case wasm::R_WASM_TABLE_INDEX_I32:
632 case wasm::R_WASM_TABLE_INDEX_I64: {
633 // Provisional value is table address of the resolved symbol itself
634 const MCSymbolWasm *Base =
635 cast<MCSymbolWasm>(Asm.getBaseSymbol(*RelEntry.Symbol));
636 assert(Base->isFunction());
637 if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
638 RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB64)
639 return TableIndices[Base] - InitialTableOffset;
640 else
641 return TableIndices[Base];
642 }
643 case wasm::R_WASM_TYPE_INDEX_LEB:
644 // Provisional value is same as the index
645 return getRelocationIndexValue(RelEntry);
646 case wasm::R_WASM_FUNCTION_INDEX_LEB:
647 case wasm::R_WASM_FUNCTION_INDEX_I32:
648 case wasm::R_WASM_GLOBAL_INDEX_LEB:
649 case wasm::R_WASM_GLOBAL_INDEX_I32:
650 case wasm::R_WASM_TAG_INDEX_LEB:
651 case wasm::R_WASM_TABLE_NUMBER_LEB:
652 // Provisional value is function/global/tag Wasm index
653 assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
654 return WasmIndices[RelEntry.Symbol];
655 case wasm::R_WASM_FUNCTION_OFFSET_I32:
656 case wasm::R_WASM_FUNCTION_OFFSET_I64:
657 case wasm::R_WASM_SECTION_OFFSET_I32: {
658 if (!RelEntry.Symbol->isDefined())
659 return 0;
660 const auto &Section =
661 static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
662 return Section.getSectionOffset() + RelEntry.Addend;
663 }
664 case wasm::R_WASM_MEMORY_ADDR_LEB:
665 case wasm::R_WASM_MEMORY_ADDR_LEB64:
666 case wasm::R_WASM_MEMORY_ADDR_SLEB:
667 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
668 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
669 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
670 case wasm::R_WASM_MEMORY_ADDR_I32:
671 case wasm::R_WASM_MEMORY_ADDR_I64:
672 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
673 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
674 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: {
675 // Provisional value is address of the global plus the offset
676 // For undefined symbols, use zero
677 if (!RelEntry.Symbol->isDefined())
678 return 0;
679 const wasm::WasmDataReference &SymRef = DataLocations[RelEntry.Symbol];
680 const WasmDataSegment &Segment = DataSegments[SymRef.Segment];
681 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
682 return Segment.Offset + SymRef.Offset + RelEntry.Addend;
683 }
684 default:
685 llvm_unreachable("invalid relocation type");
686 }
687 }
688
addData(SmallVectorImpl<char> & DataBytes,MCSectionWasm & DataSection)689 static void addData(SmallVectorImpl<char> &DataBytes,
690 MCSectionWasm &DataSection) {
691 LLVM_DEBUG(errs() << "addData: " << DataSection.getName() << "\n");
692
693 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlign()));
694
695 for (const MCFragment &Frag : DataSection) {
696 if (Frag.hasInstructions())
697 report_fatal_error("only data supported in data sections");
698
699 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
700 if (Align->getFillLen() != 1)
701 report_fatal_error("only byte values supported for alignment");
702 // If nops are requested, use zeros, as this is the data section.
703 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getFill();
704 uint64_t Size =
705 std::min<uint64_t>(alignTo(DataBytes.size(), Align->getAlignment()),
706 DataBytes.size() + Align->getMaxBytesToEmit());
707 DataBytes.resize(Size, Value);
708 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
709 int64_t NumValues;
710 if (!Fill->getNumValues().evaluateAsAbsolute(NumValues))
711 llvm_unreachable("The fill should be an assembler constant");
712 DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues,
713 Fill->getValue());
714 } else if (auto *LEB = dyn_cast<MCLEBFragment>(&Frag)) {
715 llvm::append_range(DataBytes, LEB->getContents());
716 } else {
717 llvm::append_range(DataBytes, cast<MCDataFragment>(Frag).getContents());
718 }
719 }
720
721 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
722 }
723
724 uint32_t
getRelocationIndexValue(const WasmRelocationEntry & RelEntry)725 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
726 if (RelEntry.Type == wasm::R_WASM_TYPE_INDEX_LEB) {
727 auto It = TypeIndices.find(RelEntry.Symbol);
728 if (It == TypeIndices.end())
729 report_fatal_error("symbol not found in type index space: " +
730 RelEntry.Symbol->getName());
731 return It->second;
732 }
733
734 return RelEntry.Symbol->getIndex();
735 }
736
737 // Apply the portions of the relocation records that we can handle ourselves
738 // directly.
applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,uint64_t ContentsOffset,const MCAssembler & Asm)739 void WasmObjectWriter::applyRelocations(
740 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset,
741 const MCAssembler &Asm) {
742 auto &Stream = static_cast<raw_pwrite_stream &>(W->OS);
743 for (const WasmRelocationEntry &RelEntry : Relocations) {
744 uint64_t Offset = ContentsOffset +
745 RelEntry.FixupSection->getSectionOffset() +
746 RelEntry.Offset;
747
748 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
749 uint64_t Value = getProvisionalValue(Asm, RelEntry);
750
751 switch (RelEntry.Type) {
752 case wasm::R_WASM_FUNCTION_INDEX_LEB:
753 case wasm::R_WASM_TYPE_INDEX_LEB:
754 case wasm::R_WASM_GLOBAL_INDEX_LEB:
755 case wasm::R_WASM_MEMORY_ADDR_LEB:
756 case wasm::R_WASM_TAG_INDEX_LEB:
757 case wasm::R_WASM_TABLE_NUMBER_LEB:
758 writePatchableU32(Stream, Value, Offset);
759 break;
760 case wasm::R_WASM_MEMORY_ADDR_LEB64:
761 writePatchableU64(Stream, Value, Offset);
762 break;
763 case wasm::R_WASM_TABLE_INDEX_I32:
764 case wasm::R_WASM_MEMORY_ADDR_I32:
765 case wasm::R_WASM_FUNCTION_OFFSET_I32:
766 case wasm::R_WASM_FUNCTION_INDEX_I32:
767 case wasm::R_WASM_SECTION_OFFSET_I32:
768 case wasm::R_WASM_GLOBAL_INDEX_I32:
769 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
770 patchI32(Stream, Value, Offset);
771 break;
772 case wasm::R_WASM_TABLE_INDEX_I64:
773 case wasm::R_WASM_MEMORY_ADDR_I64:
774 case wasm::R_WASM_FUNCTION_OFFSET_I64:
775 patchI64(Stream, Value, Offset);
776 break;
777 case wasm::R_WASM_TABLE_INDEX_SLEB:
778 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
779 case wasm::R_WASM_MEMORY_ADDR_SLEB:
780 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
781 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
782 writePatchableS32(Stream, Value, Offset);
783 break;
784 case wasm::R_WASM_TABLE_INDEX_SLEB64:
785 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
786 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
787 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
788 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
789 writePatchableS64(Stream, Value, Offset);
790 break;
791 default:
792 llvm_unreachable("invalid relocation type");
793 }
794 }
795 }
796
writeTypeSection(ArrayRef<wasm::WasmSignature> Signatures)797 void WasmObjectWriter::writeTypeSection(
798 ArrayRef<wasm::WasmSignature> Signatures) {
799 if (Signatures.empty())
800 return;
801
802 SectionBookkeeping Section;
803 startSection(Section, wasm::WASM_SEC_TYPE);
804
805 encodeULEB128(Signatures.size(), W->OS);
806
807 for (const wasm::WasmSignature &Sig : Signatures) {
808 W->OS << char(wasm::WASM_TYPE_FUNC);
809 encodeULEB128(Sig.Params.size(), W->OS);
810 for (wasm::ValType Ty : Sig.Params)
811 writeValueType(Ty);
812 encodeULEB128(Sig.Returns.size(), W->OS);
813 for (wasm::ValType Ty : Sig.Returns)
814 writeValueType(Ty);
815 }
816
817 endSection(Section);
818 }
819
writeImportSection(ArrayRef<wasm::WasmImport> Imports,uint64_t DataSize,uint32_t NumElements)820 void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
821 uint64_t DataSize,
822 uint32_t NumElements) {
823 if (Imports.empty())
824 return;
825
826 uint64_t NumPages =
827 (DataSize + wasm::WasmDefaultPageSize - 1) / wasm::WasmDefaultPageSize;
828
829 SectionBookkeeping Section;
830 startSection(Section, wasm::WASM_SEC_IMPORT);
831
832 encodeULEB128(Imports.size(), W->OS);
833 for (const wasm::WasmImport &Import : Imports) {
834 writeString(Import.Module);
835 writeString(Import.Field);
836 W->OS << char(Import.Kind);
837
838 switch (Import.Kind) {
839 case wasm::WASM_EXTERNAL_FUNCTION:
840 encodeULEB128(Import.SigIndex, W->OS);
841 break;
842 case wasm::WASM_EXTERNAL_GLOBAL:
843 W->OS << char(Import.Global.Type);
844 W->OS << char(Import.Global.Mutable ? 1 : 0);
845 break;
846 case wasm::WASM_EXTERNAL_MEMORY:
847 encodeULEB128(Import.Memory.Flags, W->OS);
848 encodeULEB128(NumPages, W->OS); // initial
849 break;
850 case wasm::WASM_EXTERNAL_TABLE:
851 W->OS << char(Import.Table.ElemType);
852 encodeULEB128(Import.Table.Limits.Flags, W->OS);
853 encodeULEB128(NumElements, W->OS); // initial
854 break;
855 case wasm::WASM_EXTERNAL_TAG:
856 W->OS << char(0); // Reserved 'attribute' field
857 encodeULEB128(Import.SigIndex, W->OS);
858 break;
859 default:
860 llvm_unreachable("unsupported import kind");
861 }
862 }
863
864 endSection(Section);
865 }
866
writeFunctionSection(ArrayRef<WasmFunction> Functions)867 void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
868 if (Functions.empty())
869 return;
870
871 SectionBookkeeping Section;
872 startSection(Section, wasm::WASM_SEC_FUNCTION);
873
874 encodeULEB128(Functions.size(), W->OS);
875 for (const WasmFunction &Func : Functions)
876 encodeULEB128(Func.SigIndex, W->OS);
877
878 endSection(Section);
879 }
880
writeTagSection(ArrayRef<uint32_t> TagTypes)881 void WasmObjectWriter::writeTagSection(ArrayRef<uint32_t> TagTypes) {
882 if (TagTypes.empty())
883 return;
884
885 SectionBookkeeping Section;
886 startSection(Section, wasm::WASM_SEC_TAG);
887
888 encodeULEB128(TagTypes.size(), W->OS);
889 for (uint32_t Index : TagTypes) {
890 W->OS << char(0); // Reserved 'attribute' field
891 encodeULEB128(Index, W->OS);
892 }
893
894 endSection(Section);
895 }
896
writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals)897 void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
898 if (Globals.empty())
899 return;
900
901 SectionBookkeeping Section;
902 startSection(Section, wasm::WASM_SEC_GLOBAL);
903
904 encodeULEB128(Globals.size(), W->OS);
905 for (const wasm::WasmGlobal &Global : Globals) {
906 encodeULEB128(Global.Type.Type, W->OS);
907 W->OS << char(Global.Type.Mutable);
908 if (Global.InitExpr.Extended) {
909 llvm_unreachable("extected init expressions not supported");
910 } else {
911 W->OS << char(Global.InitExpr.Inst.Opcode);
912 switch (Global.Type.Type) {
913 case wasm::WASM_TYPE_I32:
914 encodeSLEB128(0, W->OS);
915 break;
916 case wasm::WASM_TYPE_I64:
917 encodeSLEB128(0, W->OS);
918 break;
919 case wasm::WASM_TYPE_F32:
920 writeI32(0);
921 break;
922 case wasm::WASM_TYPE_F64:
923 writeI64(0);
924 break;
925 case wasm::WASM_TYPE_EXTERNREF:
926 writeValueType(wasm::ValType::EXTERNREF);
927 break;
928 default:
929 llvm_unreachable("unexpected type");
930 }
931 }
932 W->OS << char(wasm::WASM_OPCODE_END);
933 }
934
935 endSection(Section);
936 }
937
writeTableSection(ArrayRef<wasm::WasmTable> Tables)938 void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) {
939 if (Tables.empty())
940 return;
941
942 SectionBookkeeping Section;
943 startSection(Section, wasm::WASM_SEC_TABLE);
944
945 encodeULEB128(Tables.size(), W->OS);
946 for (const wasm::WasmTable &Table : Tables) {
947 assert(Table.Type.ElemType != wasm::ValType::OTHERREF &&
948 "Cannot encode general ref-typed tables");
949 encodeULEB128((uint32_t)Table.Type.ElemType, W->OS);
950 encodeULEB128(Table.Type.Limits.Flags, W->OS);
951 encodeULEB128(Table.Type.Limits.Minimum, W->OS);
952 if (Table.Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
953 encodeULEB128(Table.Type.Limits.Maximum, W->OS);
954 }
955 endSection(Section);
956 }
957
writeExportSection(ArrayRef<wasm::WasmExport> Exports)958 void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
959 if (Exports.empty())
960 return;
961
962 SectionBookkeeping Section;
963 startSection(Section, wasm::WASM_SEC_EXPORT);
964
965 encodeULEB128(Exports.size(), W->OS);
966 for (const wasm::WasmExport &Export : Exports) {
967 writeString(Export.Name);
968 W->OS << char(Export.Kind);
969 encodeULEB128(Export.Index, W->OS);
970 }
971
972 endSection(Section);
973 }
974
writeElemSection(const MCSymbolWasm * IndirectFunctionTable,ArrayRef<uint32_t> TableElems)975 void WasmObjectWriter::writeElemSection(
976 const MCSymbolWasm *IndirectFunctionTable, ArrayRef<uint32_t> TableElems) {
977 if (TableElems.empty())
978 return;
979
980 assert(IndirectFunctionTable);
981
982 SectionBookkeeping Section;
983 startSection(Section, wasm::WASM_SEC_ELEM);
984
985 encodeULEB128(1, W->OS); // number of "segments"
986
987 assert(WasmIndices.count(IndirectFunctionTable));
988 uint32_t TableNumber = WasmIndices.find(IndirectFunctionTable)->second;
989 uint32_t Flags = 0;
990 if (TableNumber)
991 Flags |= wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER;
992 encodeULEB128(Flags, W->OS);
993 if (Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
994 encodeULEB128(TableNumber, W->OS); // the table number
995
996 // init expr for starting offset
997 W->OS << char(is64Bit() ? wasm::WASM_OPCODE_I64_CONST
998 : wasm::WASM_OPCODE_I32_CONST);
999 encodeSLEB128(InitialTableOffset, W->OS);
1000 W->OS << char(wasm::WASM_OPCODE_END);
1001
1002 if (Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC) {
1003 // We only write active function table initializers, for which the elem kind
1004 // is specified to be written as 0x00 and interpreted to mean "funcref".
1005 const uint8_t ElemKind = 0;
1006 W->OS << ElemKind;
1007 }
1008
1009 encodeULEB128(TableElems.size(), W->OS);
1010 for (uint32_t Elem : TableElems)
1011 encodeULEB128(Elem, W->OS);
1012
1013 endSection(Section);
1014 }
1015
writeDataCountSection()1016 void WasmObjectWriter::writeDataCountSection() {
1017 if (DataSegments.empty())
1018 return;
1019
1020 SectionBookkeeping Section;
1021 startSection(Section, wasm::WASM_SEC_DATACOUNT);
1022 encodeULEB128(DataSegments.size(), W->OS);
1023 endSection(Section);
1024 }
1025
writeCodeSection(const MCAssembler & Asm,ArrayRef<WasmFunction> Functions)1026 uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
1027 ArrayRef<WasmFunction> Functions) {
1028 if (Functions.empty())
1029 return 0;
1030
1031 SectionBookkeeping Section;
1032 startSection(Section, wasm::WASM_SEC_CODE);
1033
1034 encodeULEB128(Functions.size(), W->OS);
1035
1036 for (const WasmFunction &Func : Functions) {
1037 auto *FuncSection = static_cast<MCSectionWasm *>(Func.Section);
1038
1039 int64_t Size = Asm.getSectionAddressSize(*FuncSection);
1040 encodeULEB128(Size, W->OS);
1041 FuncSection->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
1042 Asm.writeSectionData(W->OS, FuncSection);
1043 }
1044
1045 // Apply fixups.
1046 applyRelocations(CodeRelocations, Section.ContentsOffset, Asm);
1047
1048 endSection(Section);
1049 return Section.Index;
1050 }
1051
writeDataSection(const MCAssembler & Asm)1052 uint32_t WasmObjectWriter::writeDataSection(const MCAssembler &Asm) {
1053 if (DataSegments.empty())
1054 return 0;
1055
1056 SectionBookkeeping Section;
1057 startSection(Section, wasm::WASM_SEC_DATA);
1058
1059 encodeULEB128(DataSegments.size(), W->OS); // count
1060
1061 for (const WasmDataSegment &Segment : DataSegments) {
1062 encodeULEB128(Segment.InitFlags, W->OS); // flags
1063 if (Segment.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1064 encodeULEB128(0, W->OS); // memory index
1065 if ((Segment.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1066 W->OS << char(is64Bit() ? wasm::WASM_OPCODE_I64_CONST
1067 : wasm::WASM_OPCODE_I32_CONST);
1068 encodeSLEB128(Segment.Offset, W->OS); // offset
1069 W->OS << char(wasm::WASM_OPCODE_END);
1070 }
1071 encodeULEB128(Segment.Data.size(), W->OS); // size
1072 Segment.Section->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
1073 W->OS << Segment.Data; // data
1074 }
1075
1076 // Apply fixups.
1077 applyRelocations(DataRelocations, Section.ContentsOffset, Asm);
1078
1079 endSection(Section);
1080 return Section.Index;
1081 }
1082
writeRelocSection(uint32_t SectionIndex,StringRef Name,std::vector<WasmRelocationEntry> & Relocs)1083 void WasmObjectWriter::writeRelocSection(
1084 uint32_t SectionIndex, StringRef Name,
1085 std::vector<WasmRelocationEntry> &Relocs) {
1086 // See: https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
1087 // for descriptions of the reloc sections.
1088
1089 if (Relocs.empty())
1090 return;
1091
1092 // First, ensure the relocations are sorted in offset order. In general they
1093 // should already be sorted since `recordRelocation` is called in offset
1094 // order, but for the code section we combine many MC sections into single
1095 // wasm section, and this order is determined by the order of Asm.Symbols()
1096 // not the sections order.
1097 llvm::stable_sort(
1098 Relocs, [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) {
1099 return (A.Offset + A.FixupSection->getSectionOffset()) <
1100 (B.Offset + B.FixupSection->getSectionOffset());
1101 });
1102
1103 SectionBookkeeping Section;
1104 startCustomSection(Section, std::string("reloc.") + Name.str());
1105
1106 encodeULEB128(SectionIndex, W->OS);
1107 encodeULEB128(Relocs.size(), W->OS);
1108 for (const WasmRelocationEntry &RelEntry : Relocs) {
1109 uint64_t Offset =
1110 RelEntry.Offset + RelEntry.FixupSection->getSectionOffset();
1111 uint32_t Index = getRelocationIndexValue(RelEntry);
1112
1113 W->OS << char(RelEntry.Type);
1114 encodeULEB128(Offset, W->OS);
1115 encodeULEB128(Index, W->OS);
1116 if (RelEntry.hasAddend())
1117 encodeSLEB128(RelEntry.Addend, W->OS);
1118 }
1119
1120 endSection(Section);
1121 }
1122
writeCustomRelocSections()1123 void WasmObjectWriter::writeCustomRelocSections() {
1124 for (const auto &Sec : CustomSections) {
1125 auto &Relocations = CustomSectionsRelocations[Sec.Section];
1126 writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations);
1127 }
1128 }
1129
writeLinkingMetaDataSection(ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,ArrayRef<std::pair<uint16_t,uint32_t>> InitFuncs,const std::map<StringRef,std::vector<WasmComdatEntry>> & Comdats)1130 void WasmObjectWriter::writeLinkingMetaDataSection(
1131 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
1132 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
1133 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
1134 SectionBookkeeping Section;
1135 startCustomSection(Section, "linking");
1136 encodeULEB128(wasm::WasmMetadataVersion, W->OS);
1137
1138 SectionBookkeeping SubSection;
1139 if (SymbolInfos.size() != 0) {
1140 startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
1141 encodeULEB128(SymbolInfos.size(), W->OS);
1142 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
1143 encodeULEB128(Sym.Kind, W->OS);
1144 encodeULEB128(Sym.Flags, W->OS);
1145 switch (Sym.Kind) {
1146 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1147 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1148 case wasm::WASM_SYMBOL_TYPE_TAG:
1149 case wasm::WASM_SYMBOL_TYPE_TABLE:
1150 encodeULEB128(Sym.ElementIndex, W->OS);
1151 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 ||
1152 (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
1153 writeString(Sym.Name);
1154 break;
1155 case wasm::WASM_SYMBOL_TYPE_DATA:
1156 writeString(Sym.Name);
1157 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
1158 encodeULEB128(Sym.DataRef.Segment, W->OS);
1159 encodeULEB128(Sym.DataRef.Offset, W->OS);
1160 encodeULEB128(Sym.DataRef.Size, W->OS);
1161 }
1162 break;
1163 case wasm::WASM_SYMBOL_TYPE_SECTION: {
1164 const uint32_t SectionIndex =
1165 CustomSections[Sym.ElementIndex].OutputIndex;
1166 encodeULEB128(SectionIndex, W->OS);
1167 break;
1168 }
1169 default:
1170 llvm_unreachable("unexpected kind");
1171 }
1172 }
1173 endSection(SubSection);
1174 }
1175
1176 if (DataSegments.size()) {
1177 startSection(SubSection, wasm::WASM_SEGMENT_INFO);
1178 encodeULEB128(DataSegments.size(), W->OS);
1179 for (const WasmDataSegment &Segment : DataSegments) {
1180 writeString(Segment.Name);
1181 encodeULEB128(Segment.Alignment, W->OS);
1182 encodeULEB128(Segment.LinkingFlags, W->OS);
1183 }
1184 endSection(SubSection);
1185 }
1186
1187 if (!InitFuncs.empty()) {
1188 startSection(SubSection, wasm::WASM_INIT_FUNCS);
1189 encodeULEB128(InitFuncs.size(), W->OS);
1190 for (auto &StartFunc : InitFuncs) {
1191 encodeULEB128(StartFunc.first, W->OS); // priority
1192 encodeULEB128(StartFunc.second, W->OS); // function index
1193 }
1194 endSection(SubSection);
1195 }
1196
1197 if (Comdats.size()) {
1198 startSection(SubSection, wasm::WASM_COMDAT_INFO);
1199 encodeULEB128(Comdats.size(), W->OS);
1200 for (const auto &C : Comdats) {
1201 writeString(C.first);
1202 encodeULEB128(0, W->OS); // flags for future use
1203 encodeULEB128(C.second.size(), W->OS);
1204 for (const WasmComdatEntry &Entry : C.second) {
1205 encodeULEB128(Entry.Kind, W->OS);
1206 encodeULEB128(Entry.Index, W->OS);
1207 }
1208 }
1209 endSection(SubSection);
1210 }
1211
1212 endSection(Section);
1213 }
1214
writeCustomSection(WasmCustomSection & CustomSection,const MCAssembler & Asm)1215 void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection,
1216 const MCAssembler &Asm) {
1217 SectionBookkeeping Section;
1218 auto *Sec = CustomSection.Section;
1219 startCustomSection(Section, CustomSection.Name);
1220
1221 Sec->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
1222 Asm.writeSectionData(W->OS, Sec);
1223
1224 CustomSection.OutputContentsOffset = Section.ContentsOffset;
1225 CustomSection.OutputIndex = Section.Index;
1226
1227 endSection(Section);
1228
1229 // Apply fixups.
1230 auto &Relocations = CustomSectionsRelocations[CustomSection.Section];
1231 applyRelocations(Relocations, CustomSection.OutputContentsOffset, Asm);
1232 }
1233
getFunctionType(const MCSymbolWasm & Symbol)1234 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
1235 assert(Symbol.isFunction());
1236 assert(TypeIndices.count(&Symbol));
1237 return TypeIndices[&Symbol];
1238 }
1239
getTagType(const MCSymbolWasm & Symbol)1240 uint32_t WasmObjectWriter::getTagType(const MCSymbolWasm &Symbol) {
1241 assert(Symbol.isTag());
1242 assert(TypeIndices.count(&Symbol));
1243 return TypeIndices[&Symbol];
1244 }
1245
registerFunctionType(const MCSymbolWasm & Symbol)1246 void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
1247 assert(Symbol.isFunction());
1248
1249 wasm::WasmSignature S;
1250
1251 if (auto *Sig = Symbol.getSignature()) {
1252 S.Returns = Sig->Returns;
1253 S.Params = Sig->Params;
1254 }
1255
1256 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
1257 if (Pair.second)
1258 Signatures.push_back(S);
1259 TypeIndices[&Symbol] = Pair.first->second;
1260
1261 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1262 << " new:" << Pair.second << "\n");
1263 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
1264 }
1265
registerTagType(const MCSymbolWasm & Symbol)1266 void WasmObjectWriter::registerTagType(const MCSymbolWasm &Symbol) {
1267 assert(Symbol.isTag());
1268
1269 // TODO Currently we don't generate imported exceptions, but if we do, we
1270 // should have a way of infering types of imported exceptions.
1271 wasm::WasmSignature S;
1272 if (auto *Sig = Symbol.getSignature()) {
1273 S.Returns = Sig->Returns;
1274 S.Params = Sig->Params;
1275 }
1276
1277 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
1278 if (Pair.second)
1279 Signatures.push_back(S);
1280 TypeIndices[&Symbol] = Pair.first->second;
1281
1282 LLVM_DEBUG(dbgs() << "registerTagType: " << Symbol << " new:" << Pair.second
1283 << "\n");
1284 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
1285 }
1286
isInSymtab(const MCSymbolWasm & Sym)1287 static bool isInSymtab(const MCSymbolWasm &Sym) {
1288 if (Sym.isUsedInReloc() || Sym.isUsedInInitArray())
1289 return true;
1290
1291 if (Sym.isComdat() && !Sym.isDefined())
1292 return false;
1293
1294 if (Sym.isTemporary())
1295 return false;
1296
1297 if (Sym.isSection())
1298 return false;
1299
1300 if (Sym.omitFromLinkingSection())
1301 return false;
1302
1303 return true;
1304 }
1305
isSectionReferenced(MCAssembler & Asm,MCSectionWasm & Section)1306 static bool isSectionReferenced(MCAssembler &Asm, MCSectionWasm &Section) {
1307 StringRef SectionName = Section.getName();
1308
1309 for (const MCSymbol &S : Asm.symbols()) {
1310 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1311 if (WS.isData() && WS.isInSection()) {
1312 auto &RefSection = static_cast<MCSectionWasm &>(WS.getSection());
1313 if (RefSection.getName() == SectionName) {
1314 return true;
1315 }
1316 }
1317 }
1318
1319 return false;
1320 }
1321
prepareImports(SmallVectorImpl<wasm::WasmImport> & Imports,MCAssembler & Asm)1322 void WasmObjectWriter::prepareImports(
1323 SmallVectorImpl<wasm::WasmImport> &Imports, MCAssembler &Asm) {
1324 // For now, always emit the memory import, since loads and stores are not
1325 // valid without it. In the future, we could perhaps be more clever and omit
1326 // it if there are no loads or stores.
1327 wasm::WasmImport MemImport;
1328 MemImport.Module = "env";
1329 MemImport.Field = "__linear_memory";
1330 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
1331 MemImport.Memory.Flags = is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64
1332 : wasm::WASM_LIMITS_FLAG_NONE;
1333 Imports.push_back(MemImport);
1334
1335 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1336 // symbols. This must be done before populating WasmIndices for defined
1337 // symbols.
1338 for (const MCSymbol &S : Asm.symbols()) {
1339 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1340
1341 // Register types for all functions, including those with private linkage
1342 // (because wasm always needs a type signature).
1343 if (WS.isFunction()) {
1344 const auto *BS = Asm.getBaseSymbol(S);
1345 if (!BS)
1346 report_fatal_error(Twine(S.getName()) +
1347 ": absolute addressing not supported!");
1348 registerFunctionType(*cast<MCSymbolWasm>(BS));
1349 }
1350
1351 if (WS.isTag())
1352 registerTagType(WS);
1353
1354 if (WS.isTemporary())
1355 continue;
1356
1357 // If the symbol is not defined in this translation unit, import it.
1358 if (!WS.isDefined() && !WS.isComdat()) {
1359 if (WS.isFunction()) {
1360 wasm::WasmImport Import;
1361 Import.Module = WS.getImportModule();
1362 Import.Field = WS.getImportName();
1363 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1364 Import.SigIndex = getFunctionType(WS);
1365 Imports.push_back(Import);
1366 assert(WasmIndices.count(&WS) == 0);
1367 WasmIndices[&WS] = NumFunctionImports++;
1368 } else if (WS.isGlobal()) {
1369 if (WS.isWeak())
1370 report_fatal_error("undefined global symbol cannot be weak");
1371
1372 wasm::WasmImport Import;
1373 Import.Field = WS.getImportName();
1374 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1375 Import.Module = WS.getImportModule();
1376 Import.Global = WS.getGlobalType();
1377 Imports.push_back(Import);
1378 assert(WasmIndices.count(&WS) == 0);
1379 WasmIndices[&WS] = NumGlobalImports++;
1380 } else if (WS.isTag()) {
1381 if (WS.isWeak())
1382 report_fatal_error("undefined tag symbol cannot be weak");
1383
1384 wasm::WasmImport Import;
1385 Import.Module = WS.getImportModule();
1386 Import.Field = WS.getImportName();
1387 Import.Kind = wasm::WASM_EXTERNAL_TAG;
1388 Import.SigIndex = getTagType(WS);
1389 Imports.push_back(Import);
1390 assert(WasmIndices.count(&WS) == 0);
1391 WasmIndices[&WS] = NumTagImports++;
1392 } else if (WS.isTable()) {
1393 if (WS.isWeak())
1394 report_fatal_error("undefined table symbol cannot be weak");
1395
1396 wasm::WasmImport Import;
1397 Import.Module = WS.getImportModule();
1398 Import.Field = WS.getImportName();
1399 Import.Kind = wasm::WASM_EXTERNAL_TABLE;
1400 Import.Table = WS.getTableType();
1401 Imports.push_back(Import);
1402 assert(WasmIndices.count(&WS) == 0);
1403 WasmIndices[&WS] = NumTableImports++;
1404 }
1405 }
1406 }
1407
1408 // Add imports for GOT globals
1409 for (const MCSymbol &S : Asm.symbols()) {
1410 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1411 if (WS.isUsedInGOT()) {
1412 wasm::WasmImport Import;
1413 if (WS.isFunction())
1414 Import.Module = "GOT.func";
1415 else
1416 Import.Module = "GOT.mem";
1417 Import.Field = WS.getName();
1418 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1419 Import.Global = {wasm::WASM_TYPE_I32, true};
1420 Imports.push_back(Import);
1421 assert(GOTIndices.count(&WS) == 0);
1422 GOTIndices[&WS] = NumGlobalImports++;
1423 }
1424 }
1425 }
1426
writeObject()1427 uint64_t WasmObjectWriter::writeObject() {
1428 support::endian::Writer MainWriter(*OS, llvm::endianness::little);
1429 W = &MainWriter;
1430 if (IsSplitDwarf) {
1431 uint64_t TotalSize = writeOneObject(*Asm, DwoMode::NonDwoOnly);
1432 assert(DwoOS);
1433 support::endian::Writer DwoWriter(*DwoOS, llvm::endianness::little);
1434 W = &DwoWriter;
1435 return TotalSize + writeOneObject(*Asm, DwoMode::DwoOnly);
1436 } else {
1437 return writeOneObject(*Asm, DwoMode::AllSections);
1438 }
1439 }
1440
writeOneObject(MCAssembler & Asm,DwoMode Mode)1441 uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
1442 DwoMode Mode) {
1443 uint64_t StartOffset = W->OS.tell();
1444 SectionCount = 0;
1445 CustomSections.clear();
1446
1447 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1448
1449 // Collect information from the available symbols.
1450 SmallVector<WasmFunction, 4> Functions;
1451 SmallVector<uint32_t, 4> TableElems;
1452 SmallVector<wasm::WasmImport, 4> Imports;
1453 SmallVector<wasm::WasmExport, 4> Exports;
1454 SmallVector<uint32_t, 2> TagTypes;
1455 SmallVector<wasm::WasmGlobal, 1> Globals;
1456 SmallVector<wasm::WasmTable, 1> Tables;
1457 SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
1458 SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
1459 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
1460 uint64_t DataSize = 0;
1461 if (Mode != DwoMode::DwoOnly)
1462 prepareImports(Imports, Asm);
1463
1464 // Populate DataSegments and CustomSections, which must be done before
1465 // populating DataLocations.
1466 for (MCSection &Sec : Asm) {
1467 auto &Section = static_cast<MCSectionWasm &>(Sec);
1468 StringRef SectionName = Section.getName();
1469
1470 if (Mode == DwoMode::NonDwoOnly && isDwoSection(Sec))
1471 continue;
1472 if (Mode == DwoMode::DwoOnly && !isDwoSection(Sec))
1473 continue;
1474
1475 LLVM_DEBUG(dbgs() << "Processing Section " << SectionName << " group "
1476 << Section.getGroup() << "\n";);
1477
1478 // .init_array sections are handled specially elsewhere, include them in
1479 // data segments if and only if referenced by a symbol.
1480 if (SectionName.starts_with(".init_array") &&
1481 !isSectionReferenced(Asm, Section))
1482 continue;
1483
1484 // Code is handled separately
1485 if (Section.isText())
1486 continue;
1487
1488 if (Section.isWasmData()) {
1489 uint32_t SegmentIndex = DataSegments.size();
1490 DataSize = alignTo(DataSize, Section.getAlign());
1491 DataSegments.emplace_back();
1492 WasmDataSegment &Segment = DataSegments.back();
1493 Segment.Name = SectionName;
1494 Segment.InitFlags = Section.getPassive()
1495 ? (uint32_t)wasm::WASM_DATA_SEGMENT_IS_PASSIVE
1496 : 0;
1497 Segment.Offset = DataSize;
1498 Segment.Section = &Section;
1499 addData(Segment.Data, Section);
1500 Segment.Alignment = Log2(Section.getAlign());
1501 Segment.LinkingFlags = Section.getSegmentFlags();
1502 DataSize += Segment.Data.size();
1503 Section.setSegmentIndex(SegmentIndex);
1504
1505 if (const MCSymbolWasm *C = Section.getGroup()) {
1506 Comdats[C->getName()].emplace_back(
1507 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
1508 }
1509 } else {
1510 // Create custom sections
1511 assert(Section.isMetadata());
1512
1513 StringRef Name = SectionName;
1514
1515 // For user-defined custom sections, strip the prefix
1516 Name.consume_front(".custom_section.");
1517
1518 MCSymbol *Begin = Sec.getBeginSymbol();
1519 if (Begin) {
1520 assert(WasmIndices.count(cast<MCSymbolWasm>(Begin)) == 0);
1521 WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size();
1522 }
1523
1524 // Separate out the producers and target features sections
1525 if (Name == "producers") {
1526 ProducersSection = std::make_unique<WasmCustomSection>(Name, &Section);
1527 continue;
1528 }
1529 if (Name == "target_features") {
1530 TargetFeaturesSection =
1531 std::make_unique<WasmCustomSection>(Name, &Section);
1532 continue;
1533 }
1534
1535 // Custom sections can also belong to COMDAT groups. In this case the
1536 // decriptor's "index" field is the section index (in the final object
1537 // file), but that is not known until after layout, so it must be fixed up
1538 // later
1539 if (const MCSymbolWasm *C = Section.getGroup()) {
1540 Comdats[C->getName()].emplace_back(
1541 WasmComdatEntry{wasm::WASM_COMDAT_SECTION,
1542 static_cast<uint32_t>(CustomSections.size())});
1543 }
1544
1545 CustomSections.emplace_back(Name, &Section);
1546 }
1547 }
1548
1549 if (Mode != DwoMode::DwoOnly) {
1550 // Populate WasmIndices and DataLocations for defined symbols.
1551 for (const MCSymbol &S : Asm.symbols()) {
1552 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1553 // or used in relocations.
1554 if (S.isTemporary() && S.getName().empty())
1555 continue;
1556
1557 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1558 LLVM_DEBUG(
1559 dbgs() << "MCSymbol: "
1560 << toString(WS.getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA))
1561 << " '" << S << "'"
1562 << " isDefined=" << S.isDefined() << " isExternal="
1563 << S.isExternal() << " isTemporary=" << S.isTemporary()
1564 << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden()
1565 << " isVariable=" << WS.isVariable() << "\n");
1566
1567 if (WS.isVariable())
1568 continue;
1569 if (WS.isComdat() && !WS.isDefined())
1570 continue;
1571
1572 if (WS.isFunction()) {
1573 unsigned Index;
1574 if (WS.isDefined()) {
1575 if (WS.getOffset() != 0)
1576 report_fatal_error(
1577 "function sections must contain one function each");
1578
1579 // A definition. Write out the function body.
1580 Index = NumFunctionImports + Functions.size();
1581 WasmFunction Func;
1582 Func.SigIndex = getFunctionType(WS);
1583 Func.Section = &WS.getSection();
1584 assert(WasmIndices.count(&WS) == 0);
1585 WasmIndices[&WS] = Index;
1586 Functions.push_back(Func);
1587
1588 auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
1589 if (const MCSymbolWasm *C = Section.getGroup()) {
1590 Comdats[C->getName()].emplace_back(
1591 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
1592 }
1593
1594 if (WS.hasExportName()) {
1595 wasm::WasmExport Export;
1596 Export.Name = WS.getExportName();
1597 Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1598 Export.Index = Index;
1599 Exports.push_back(Export);
1600 }
1601 } else {
1602 // An import; the index was assigned above.
1603 Index = WasmIndices.find(&WS)->second;
1604 }
1605
1606 LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
1607
1608 } else if (WS.isData()) {
1609 if (!isInSymtab(WS))
1610 continue;
1611
1612 if (!WS.isDefined()) {
1613 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1614 << "\n");
1615 continue;
1616 }
1617
1618 if (!WS.getSize())
1619 report_fatal_error("data symbols must have a size set with .size: " +
1620 WS.getName());
1621
1622 int64_t Size = 0;
1623 if (!WS.getSize()->evaluateAsAbsolute(Size, Asm))
1624 report_fatal_error(".size expression must be evaluatable");
1625
1626 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
1627 if (!DataSection.isWasmData())
1628 report_fatal_error("data symbols must live in a data section: " +
1629 WS.getName());
1630
1631 // For each data symbol, export it in the symtab as a reference to the
1632 // corresponding Wasm data segment.
1633 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1634 DataSection.getSegmentIndex(), Asm.getSymbolOffset(WS),
1635 static_cast<uint64_t>(Size)};
1636 assert(DataLocations.count(&WS) == 0);
1637 DataLocations[&WS] = Ref;
1638 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
1639
1640 } else if (WS.isGlobal()) {
1641 // A "true" Wasm global (currently just __stack_pointer)
1642 if (WS.isDefined()) {
1643 wasm::WasmGlobal Global;
1644 Global.Type = WS.getGlobalType();
1645 Global.Index = NumGlobalImports + Globals.size();
1646 Global.InitExpr.Extended = false;
1647 switch (Global.Type.Type) {
1648 case wasm::WASM_TYPE_I32:
1649 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1650 break;
1651 case wasm::WASM_TYPE_I64:
1652 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_I64_CONST;
1653 break;
1654 case wasm::WASM_TYPE_F32:
1655 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_F32_CONST;
1656 break;
1657 case wasm::WASM_TYPE_F64:
1658 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_F64_CONST;
1659 break;
1660 case wasm::WASM_TYPE_EXTERNREF:
1661 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_REF_NULL;
1662 break;
1663 default:
1664 llvm_unreachable("unexpected type");
1665 }
1666 assert(WasmIndices.count(&WS) == 0);
1667 WasmIndices[&WS] = Global.Index;
1668 Globals.push_back(Global);
1669 } else {
1670 // An import; the index was assigned above
1671 LLVM_DEBUG(dbgs() << " -> global index: "
1672 << WasmIndices.find(&WS)->second << "\n");
1673 }
1674 } else if (WS.isTable()) {
1675 if (WS.isDefined()) {
1676 wasm::WasmTable Table;
1677 Table.Index = NumTableImports + Tables.size();
1678 Table.Type = WS.getTableType();
1679 assert(WasmIndices.count(&WS) == 0);
1680 WasmIndices[&WS] = Table.Index;
1681 Tables.push_back(Table);
1682 }
1683 LLVM_DEBUG(dbgs() << " -> table index: "
1684 << WasmIndices.find(&WS)->second << "\n");
1685 } else if (WS.isTag()) {
1686 // C++ exception symbol (__cpp_exception) or longjmp symbol
1687 // (__c_longjmp)
1688 unsigned Index;
1689 if (WS.isDefined()) {
1690 Index = NumTagImports + TagTypes.size();
1691 uint32_t SigIndex = getTagType(WS);
1692 assert(WasmIndices.count(&WS) == 0);
1693 WasmIndices[&WS] = Index;
1694 TagTypes.push_back(SigIndex);
1695 } else {
1696 // An import; the index was assigned above.
1697 assert(WasmIndices.count(&WS) > 0);
1698 }
1699 LLVM_DEBUG(dbgs() << " -> tag index: " << WasmIndices.find(&WS)->second
1700 << "\n");
1701
1702 } else {
1703 assert(WS.isSection());
1704 }
1705 }
1706
1707 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1708 // process these in a separate pass because we need to have processed the
1709 // target of the alias before the alias itself and the symbols are not
1710 // necessarily ordered in this way.
1711 for (const MCSymbol &S : Asm.symbols()) {
1712 if (!S.isVariable())
1713 continue;
1714
1715 assert(S.isDefined());
1716
1717 const auto *BS = Asm.getBaseSymbol(S);
1718 if (!BS)
1719 report_fatal_error(Twine(S.getName()) +
1720 ": absolute addressing not supported!");
1721 const MCSymbolWasm *Base = cast<MCSymbolWasm>(BS);
1722
1723 // Find the target symbol of this weak alias and export that index
1724 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1725 LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *Base
1726 << "'\n");
1727
1728 if (Base->isFunction()) {
1729 assert(WasmIndices.count(Base) > 0);
1730 uint32_t WasmIndex = WasmIndices.find(Base)->second;
1731 assert(WasmIndices.count(&WS) == 0);
1732 WasmIndices[&WS] = WasmIndex;
1733 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
1734 } else if (Base->isData()) {
1735 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
1736 uint64_t Offset = Asm.getSymbolOffset(S);
1737 int64_t Size = 0;
1738 // For data symbol alias we use the size of the base symbol as the
1739 // size of the alias. When an offset from the base is involved this
1740 // can result in a offset + size goes past the end of the data section
1741 // which out object format doesn't support. So we must clamp it.
1742 if (!Base->getSize()->evaluateAsAbsolute(Size, Asm))
1743 report_fatal_error(".size expression must be evaluatable");
1744 const WasmDataSegment &Segment =
1745 DataSegments[DataSection.getSegmentIndex()];
1746 Size =
1747 std::min(static_cast<uint64_t>(Size), Segment.Data.size() - Offset);
1748 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1749 DataSection.getSegmentIndex(),
1750 static_cast<uint32_t>(Asm.getSymbolOffset(S)),
1751 static_cast<uint32_t>(Size)};
1752 DataLocations[&WS] = Ref;
1753 LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
1754 } else {
1755 report_fatal_error("don't yet support global/tag aliases");
1756 }
1757 }
1758 }
1759
1760 // Finally, populate the symbol table itself, in its "natural" order.
1761 for (const MCSymbol &S : Asm.symbols()) {
1762 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1763 if (!isInSymtab(WS)) {
1764 WS.setIndex(InvalidIndex);
1765 continue;
1766 }
1767 // In bitcode generated by split-LTO-unit mode in ThinLTO, these lines can
1768 // appear:
1769 // module asm ".lto_set_conditional symbolA,symbolA.[moduleId]"
1770 // ...
1771 // (Here [moduleId] will be replaced by a real module hash ID)
1772 //
1773 // Here the original symbol (symbolA here) has been renamed to the new name
1774 // created by attaching its module ID, so the original symbol does not
1775 // appear in the bitcode anymore, and thus not in DataLocations. We should
1776 // ignore them.
1777 if (WS.isData() && WS.isDefined() && !DataLocations.count(&WS))
1778 continue;
1779 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
1780
1781 uint32_t Flags = 0;
1782 if (WS.isWeak())
1783 Flags |= wasm::WASM_SYMBOL_BINDING_WEAK;
1784 if (WS.isHidden())
1785 Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
1786 if (!WS.isExternal() && WS.isDefined())
1787 Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
1788 if (WS.isUndefined())
1789 Flags |= wasm::WASM_SYMBOL_UNDEFINED;
1790 if (WS.isNoStrip()) {
1791 Flags |= wasm::WASM_SYMBOL_NO_STRIP;
1792 if (isEmscripten()) {
1793 Flags |= wasm::WASM_SYMBOL_EXPORTED;
1794 }
1795 }
1796 if (WS.hasImportName())
1797 Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
1798 if (WS.hasExportName())
1799 Flags |= wasm::WASM_SYMBOL_EXPORTED;
1800 if (WS.isTLS())
1801 Flags |= wasm::WASM_SYMBOL_TLS;
1802
1803 wasm::WasmSymbolInfo Info;
1804 Info.Name = WS.getName();
1805 Info.Kind = WS.getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA);
1806 Info.Flags = Flags;
1807 if (!WS.isData()) {
1808 assert(WasmIndices.count(&WS) > 0);
1809 Info.ElementIndex = WasmIndices.find(&WS)->second;
1810 } else if (WS.isDefined()) {
1811 assert(DataLocations.count(&WS) > 0);
1812 Info.DataRef = DataLocations.find(&WS)->second;
1813 }
1814 WS.setIndex(SymbolInfos.size());
1815 SymbolInfos.emplace_back(Info);
1816 }
1817
1818 {
1819 auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
1820 // Functions referenced by a relocation need to put in the table. This is
1821 // purely to make the object file's provisional values readable, and is
1822 // ignored by the linker, which re-calculates the relocations itself.
1823 if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
1824 Rel.Type != wasm::R_WASM_TABLE_INDEX_I64 &&
1825 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB &&
1826 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB64 &&
1827 Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB &&
1828 Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB64)
1829 return;
1830 assert(Rel.Symbol->isFunction());
1831 const MCSymbolWasm *Base =
1832 cast<MCSymbolWasm>(Asm.getBaseSymbol(*Rel.Symbol));
1833 uint32_t FunctionIndex = WasmIndices.find(Base)->second;
1834 uint32_t TableIndex = TableElems.size() + InitialTableOffset;
1835 if (TableIndices.try_emplace(Base, TableIndex).second) {
1836 LLVM_DEBUG(dbgs() << " -> adding " << Base->getName()
1837 << " to table: " << TableIndex << "\n");
1838 TableElems.push_back(FunctionIndex);
1839 registerFunctionType(*Base);
1840 }
1841 };
1842
1843 for (const WasmRelocationEntry &RelEntry : CodeRelocations)
1844 HandleReloc(RelEntry);
1845 for (const WasmRelocationEntry &RelEntry : DataRelocations)
1846 HandleReloc(RelEntry);
1847 }
1848
1849 // Translate .init_array section contents into start functions.
1850 for (const MCSection &S : Asm) {
1851 const auto &WS = static_cast<const MCSectionWasm &>(S);
1852 if (WS.getName().starts_with(".fini_array"))
1853 report_fatal_error(".fini_array sections are unsupported");
1854 if (!WS.getName().starts_with(".init_array"))
1855 continue;
1856 auto IT = WS.begin();
1857 if (IT == WS.end())
1858 continue;
1859 const MCFragment &EmptyFrag = *IT;
1860 if (EmptyFrag.getKind() != MCFragment::FT_Data)
1861 report_fatal_error(".init_array section should be aligned");
1862
1863 const MCFragment *nextFrag = EmptyFrag.getNext();
1864 while (nextFrag != nullptr) {
1865 const MCFragment &AlignFrag = *nextFrag;
1866 if (AlignFrag.getKind() != MCFragment::FT_Align)
1867 report_fatal_error(".init_array section should be aligned");
1868 if (cast<MCAlignFragment>(AlignFrag).getAlignment() !=
1869 Align(is64Bit() ? 8 : 4))
1870 report_fatal_error(
1871 ".init_array section should be aligned for pointers");
1872
1873 const MCFragment &Frag = *AlignFrag.getNext();
1874 nextFrag = Frag.getNext();
1875 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1876 report_fatal_error("only data supported in .init_array section");
1877
1878 uint16_t Priority = UINT16_MAX;
1879 unsigned PrefixLength = strlen(".init_array");
1880 if (WS.getName().size() > PrefixLength) {
1881 if (WS.getName()[PrefixLength] != '.')
1882 report_fatal_error(
1883 ".init_array section priority should start with '.'");
1884 if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority))
1885 report_fatal_error("invalid .init_array section priority");
1886 }
1887 const auto &DataFrag = cast<MCDataFragment>(Frag);
1888 assert(llvm::all_of(DataFrag.getContents(), [](char C) { return !C; }));
1889 for (const MCFixup &Fixup : DataFrag.getFixups()) {
1890 assert(Fixup.getKind() ==
1891 MCFixup::getDataKindForSize(is64Bit() ? 8 : 4));
1892 const MCExpr *Expr = Fixup.getValue();
1893 auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr);
1894 if (!SymRef)
1895 report_fatal_error(
1896 "fixups in .init_array should be symbol references");
1897 const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol());
1898 if (TargetSym.getIndex() == InvalidIndex)
1899 report_fatal_error("symbols in .init_array should exist in symtab");
1900 if (!TargetSym.isFunction())
1901 report_fatal_error("symbols in .init_array should be for functions");
1902 InitFuncs.push_back(std::make_pair(Priority, TargetSym.getIndex()));
1903 }
1904 }
1905 }
1906
1907 // Write out the Wasm header.
1908 writeHeader(Asm);
1909
1910 uint32_t CodeSectionIndex, DataSectionIndex;
1911 if (Mode != DwoMode::DwoOnly) {
1912 writeTypeSection(Signatures);
1913 writeImportSection(Imports, DataSize, TableElems.size());
1914 writeFunctionSection(Functions);
1915 writeTableSection(Tables);
1916 // Skip the "memory" section; we import the memory instead.
1917 writeTagSection(TagTypes);
1918 writeGlobalSection(Globals);
1919 writeExportSection(Exports);
1920 const MCSymbol *IndirectFunctionTable =
1921 getContext().lookupSymbol("__indirect_function_table");
1922 writeElemSection(cast_or_null<const MCSymbolWasm>(IndirectFunctionTable),
1923 TableElems);
1924 writeDataCountSection();
1925
1926 CodeSectionIndex = writeCodeSection(Asm, Functions);
1927 DataSectionIndex = writeDataSection(Asm);
1928 }
1929
1930 // The Sections in the COMDAT list have placeholder indices (their index among
1931 // custom sections, rather than among all sections). Fix them up here.
1932 for (auto &Group : Comdats) {
1933 for (auto &Entry : Group.second) {
1934 if (Entry.Kind == wasm::WASM_COMDAT_SECTION) {
1935 Entry.Index += SectionCount;
1936 }
1937 }
1938 }
1939 for (auto &CustomSection : CustomSections)
1940 writeCustomSection(CustomSection, Asm);
1941
1942 if (Mode != DwoMode::DwoOnly) {
1943 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
1944
1945 writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
1946 writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
1947 }
1948 writeCustomRelocSections();
1949 if (ProducersSection)
1950 writeCustomSection(*ProducersSection, Asm);
1951 if (TargetFeaturesSection)
1952 writeCustomSection(*TargetFeaturesSection, Asm);
1953
1954 // TODO: Translate the .comment section to the output.
1955 return W->OS.tell() - StartOffset;
1956 }
1957
1958 std::unique_ptr<MCObjectWriter>
createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,raw_pwrite_stream & OS)1959 llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1960 raw_pwrite_stream &OS) {
1961 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
1962 }
1963
1964 std::unique_ptr<MCObjectWriter>
createWasmDwoObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,raw_pwrite_stream & OS,raw_pwrite_stream & DwoOS)1965 llvm::createWasmDwoObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1966 raw_pwrite_stream &OS,
1967 raw_pwrite_stream &DwoOS) {
1968 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS, DwoOS);
1969 }
1970