LLVM 23.0.0git
WasmObjectWriter.cpp
Go to the documentation of this file.
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"
16#include "llvm/Config/llvm-config.h"
18#include "llvm/MC/MCAssembler.h"
19#include "llvm/MC/MCContext.h"
20#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCValue.h"
27#include "llvm/Support/Debug.h"
30#include "llvm/Support/LEB128.h"
31#include <vector>
32
33using namespace llvm;
34
35#define DEBUG_TYPE "mc"
36
37namespace {
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.
41static 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.
46struct 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.
60struct WasmDataSegment {
61 MCSectionWasm *Section;
62 StringRef Name;
63 uint32_t InitFlags;
65 uint32_t Alignment;
66 uint32_t LinkingFlags;
68};
69
70// A wasm function to be written into the function section.
71struct WasmFunction {
72 uint32_t SigIndex;
73 MCSection *Section;
74};
75
76// A wasm global to be written into the global section.
77struct WasmGlobal {
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.
85struct WasmComdatEntry {
86 unsigned Kind;
87 uint32_t Index;
88};
89
90// Information about a single relocation.
91struct 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
98 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
104 bool hasAddend() const { return wasm::relocTypeHasAddend(Type); }
105
106 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)
113 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
114#endif
115};
116
117static const uint32_t InvalidIndex = -1;
118
119struct WasmCustomSection {
120
121 StringRef Name;
122 MCSectionWasm *Section;
123
124 uint32_t OutputContentsOffset = 0;
125 uint32_t OutputIndex = InvalidIndex;
126
127 WasmCustomSection(StringRef Name, MCSectionWasm *Section)
128 : Name(Name), Section(Section) {}
129};
130
131#if !defined(NDEBUG)
132raw_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.
140template <typename T, int W>
141void 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.
150template <typename T, int W>
151void 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
158static void writePatchableU32(raw_pwrite_stream &Stream, uint32_t Value,
160 writePatchableULEB<uint32_t, 5>(Stream, Value, Offset);
161}
162
163static void writePatchableS32(raw_pwrite_stream &Stream, int32_t Value,
165 writePatchableSLEB<int32_t, 5>(Stream, Value, Offset);
166}
167
168static void writePatchableU64(raw_pwrite_stream &Stream, uint64_t Value,
170 writePatchableSLEB<uint64_t, 10>(Stream, Value, Offset);
171}
172
173static void writePatchableS64(raw_pwrite_stream &Stream, int64_t Value,
175 writePatchableSLEB<int64_t, 10>(Stream, Value, Offset);
176}
177
178// Write Value as a plain integer value at offset Offset in Stream.
179static void patchI32(raw_pwrite_stream &Stream, uint32_t Value,
181 uint8_t Buffer[4];
183 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
184}
185
186static void patchI64(raw_pwrite_stream &Stream, uint64_t Value,
188 uint8_t Buffer[8];
190 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
191}
192
193bool isDwoSection(const MCSection &Sec) {
194 return Sec.getName().ends_with(".dwo");
195}
196
197class 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
211 // Maps function symbols to the table element index space. Used
212 // for TABLE_INDEX relocation types (i.e. address taken functions).
214 // Maps function/global/table symbols to the
215 // function/global/table/tag/section index space.
218 // Maps data symbols to the Wasm segment and offset/size with the segment.
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.
228 CustomSectionsRelocations;
229
230 // Map from section to defining function symbol.
232
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.
252 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
253 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
259public:
260 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
262 : TargetObjectWriter(std::move(MOTW)), OS(&OS_) {}
263
264 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
266 : TargetObjectWriter(std::move(MOTW)), IsSplitDwarf(true), OS(&OS_),
267 DwoOS(&DwoOS_) {}
268
269private:
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;
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
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
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
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
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(
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.
364void 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?
383void 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
403void 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.
425void 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.
445void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
447 W->write<uint32_t>(wasm::WasmVersion);
448}
449
450void 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
477void 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 = static_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 auto &SymB = static_cast<const 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 auto *SymA = static_cast<const 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 if (mc::isRelocRelocation(Fixup.getKind()))
534 else
535 Type =
536 TargetObjectWriter->getRelocType(Target, Fixup, FixupSection, IsLocRel);
537
538 // Absolute offset within a section or a function.
539 // Currently only supported for metadata sections.
540 // See: test/MC/WebAssembly/blockaddress.ll
541 if ((Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
542 Type == wasm::R_WASM_FUNCTION_OFFSET_I64 ||
543 Type == wasm::R_WASM_SECTION_OFFSET_I32) &&
544 SymA->isDefined()) {
545 // SymA can be a temp data symbol that represents a function (in which case
546 // it needs to be replaced by the section symbol), [XXX and it apparently
547 // later gets changed again to a func symbol?] or it can be a real
548 // function symbol, in which case it can be left as-is.
549
550 if (!FixupSection.isMetadata())
551 report_fatal_error("relocations for function or section offsets are "
552 "only supported in metadata sections");
553
554 const MCSymbol *SectionSymbol = nullptr;
555 const MCSection &SecA = SymA->getSection();
556 if (SecA.isText()) {
557 auto SecSymIt = SectionFunctions.find(&SecA);
558 if (SecSymIt == SectionFunctions.end())
559 report_fatal_error("section doesn\'t have defining symbol");
560 SectionSymbol = SecSymIt->second;
561 } else {
562 SectionSymbol = SecA.getBeginSymbol();
563 }
564 if (!SectionSymbol)
565 report_fatal_error("section symbol is required for relocation");
566
567 C += Asm->getSymbolOffset(*SymA);
568 SymA = static_cast<const MCSymbolWasm *>(SectionSymbol);
569 }
570
571 if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
572 Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB64 ||
573 Type == wasm::R_WASM_TABLE_INDEX_SLEB ||
574 Type == wasm::R_WASM_TABLE_INDEX_SLEB64 ||
575 Type == wasm::R_WASM_TABLE_INDEX_I32 ||
576 Type == wasm::R_WASM_TABLE_INDEX_I64) {
577 // TABLE_INDEX relocs implicitly use the default indirect function table.
578 // We require the function table to have already been defined.
579 auto TableName = "__indirect_function_table";
580 auto *Sym = static_cast<MCSymbolWasm *>(Ctx.lookupSymbol(TableName));
581 if (!Sym) {
582 report_fatal_error("missing indirect function table symbol");
583 } else {
584 if (!Sym->isFunctionTable())
585 report_fatal_error("__indirect_function_table symbol has wrong type");
586 // Ensure that __indirect_function_table reaches the output.
587 Sym->setNoStrip();
588 Asm->registerSymbol(*Sym);
589 }
590 }
591
592 // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
593 // against a named symbol.
594 if (Type != wasm::R_WASM_TYPE_INDEX_LEB) {
595 if (SymA->getName().empty())
596 report_fatal_error("relocations against un-named temporaries are not yet "
597 "supported by wasm");
598
599 SymA->setUsedInReloc();
600 }
601
602 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
603 LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
604
605 if (FixupSection.isWasmData()) {
606 DataRelocations.push_back(Rec);
607 } else if (FixupSection.isText()) {
608 CodeRelocations.push_back(Rec);
609 } else if (FixupSection.isMetadata()) {
610 CustomSectionsRelocations[&FixupSection].push_back(Rec);
611 } else {
612 llvm_unreachable("unexpected section type");
613 }
614}
615
616// Compute a value to write into the code at the location covered
617// by RelEntry. This value isn't used by the static linker; it just serves
618// to make the object format more readable and more likely to be directly
619// useable.
620uint64_t
621WasmObjectWriter::getProvisionalValue(const MCAssembler &Asm,
622 const WasmRelocationEntry &RelEntry) {
623 if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB ||
624 RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) &&
625 !RelEntry.Symbol->isGlobal()) {
626 assert(GOTIndices.contains(RelEntry.Symbol) && "symbol not found in GOT");
627 return GOTIndices[RelEntry.Symbol];
628 }
629
630 switch (RelEntry.Type) {
631 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
632 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
633 case wasm::R_WASM_TABLE_INDEX_SLEB:
634 case wasm::R_WASM_TABLE_INDEX_SLEB64:
635 case wasm::R_WASM_TABLE_INDEX_I32:
636 case wasm::R_WASM_TABLE_INDEX_I64: {
637 // Provisional value is table address of the resolved symbol itself
638 auto *Base =
639 static_cast<const MCSymbolWasm *>(Asm.getBaseSymbol(*RelEntry.Symbol));
640 assert(Base->isFunction());
641 if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB ||
642 RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB64)
643 return TableIndices[Base] - InitialTableOffset;
644 else
645 return TableIndices[Base];
646 }
647 case wasm::R_WASM_TYPE_INDEX_LEB:
648 // Provisional value is same as the index
649 return getRelocationIndexValue(RelEntry);
650 case wasm::R_WASM_FUNCTION_INDEX_LEB:
651 case wasm::R_WASM_FUNCTION_INDEX_I32:
652 case wasm::R_WASM_GLOBAL_INDEX_LEB:
653 case wasm::R_WASM_GLOBAL_INDEX_I32:
654 case wasm::R_WASM_TAG_INDEX_LEB:
655 case wasm::R_WASM_TABLE_NUMBER_LEB:
656 // Provisional value is function/global/tag Wasm index
657 assert(WasmIndices.contains(RelEntry.Symbol) &&
658 "symbol not found in wasm index space");
659 return WasmIndices[RelEntry.Symbol];
660 case wasm::R_WASM_FUNCTION_OFFSET_I32:
661 case wasm::R_WASM_FUNCTION_OFFSET_I64:
662 case wasm::R_WASM_SECTION_OFFSET_I32: {
663 if (!RelEntry.Symbol->isDefined())
664 return 0;
665 const auto &Section =
666 static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
667 return Section.getSectionOffset() + RelEntry.Addend;
668 }
669 case wasm::R_WASM_MEMORY_ADDR_LEB:
670 case wasm::R_WASM_MEMORY_ADDR_LEB64:
671 case wasm::R_WASM_MEMORY_ADDR_SLEB:
672 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
673 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
674 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
675 case wasm::R_WASM_MEMORY_ADDR_I32:
676 case wasm::R_WASM_MEMORY_ADDR_I64:
677 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
678 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
679 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
680 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I64: {
681 // Provisional value is address of the global plus the offset
682 // For undefined symbols, use zero
683 if (!RelEntry.Symbol->isDefined())
684 return 0;
685 const wasm::WasmDataReference &SymRef = DataLocations[RelEntry.Symbol];
686 const WasmDataSegment &Segment = DataSegments[SymRef.Segment];
687 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
688 return Segment.Offset + SymRef.Offset + RelEntry.Addend;
689 }
690 default:
691 llvm_unreachable("invalid relocation type");
692 }
693}
694
695static void addData(SmallVectorImpl<char> &DataBytes,
696 MCSectionWasm &DataSection) {
697 LLVM_DEBUG(errs() << "addData: " << DataSection.getName() << "\n");
698
699 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlign()));
700
701 for (const MCFragment &Frag : DataSection) {
702 if (Frag.hasInstructions())
703 report_fatal_error("only data supported in data sections");
704
705 llvm::append_range(DataBytes, Frag.getContents());
706 if (Frag.getKind() == MCFragment::FT_Align) {
707 if (Frag.getAlignFillLen() != 1)
708 report_fatal_error("only byte values supported for alignment");
709 // If nops are requested, use zeros, as this is the data section.
710 uint8_t Value = Frag.hasAlignEmitNops() ? 0 : Frag.getAlignFill();
711 uint64_t Size =
712 std::min<uint64_t>(alignTo(DataBytes.size(), Frag.getAlignment()),
713 DataBytes.size() + Frag.getAlignMaxBytesToEmit());
714 DataBytes.resize(Size, Value);
715 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
716 int64_t NumValues;
717 if (!Fill->getNumValues().evaluateAsAbsolute(NumValues))
718 llvm_unreachable("The fill should be an assembler constant");
719 DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues,
720 Fill->getValue());
721 } else if (Frag.getKind() == MCFragment::FT_LEB) {
722 llvm::append_range(DataBytes, Frag.getVarContents());
723 } else {
724 assert(Frag.getKind() == MCFragment::FT_Data);
725 }
726 }
727
728 LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
729}
730
731uint32_t
732WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
733 if (RelEntry.Type == wasm::R_WASM_TYPE_INDEX_LEB) {
734 auto It = TypeIndices.find(RelEntry.Symbol);
735 if (It == TypeIndices.end())
736 report_fatal_error("symbol not found in type index space: " +
737 RelEntry.Symbol->getName());
738 return It->second;
739 }
740
741 return RelEntry.Symbol->getIndex();
742}
743
744// Apply the portions of the relocation records that we can handle ourselves
745// directly.
746void WasmObjectWriter::applyRelocations(
747 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset,
748 const MCAssembler &Asm) {
749 auto &Stream = static_cast<raw_pwrite_stream &>(W->OS);
750 for (const WasmRelocationEntry &RelEntry : Relocations) {
751 uint64_t Offset = ContentsOffset +
752 RelEntry.FixupSection->getSectionOffset() +
753 RelEntry.Offset;
754
755 LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
756 uint64_t Value = getProvisionalValue(Asm, RelEntry);
757
758 switch (RelEntry.Type) {
759 case wasm::R_WASM_FUNCTION_INDEX_LEB:
760 case wasm::R_WASM_TYPE_INDEX_LEB:
761 case wasm::R_WASM_GLOBAL_INDEX_LEB:
762 case wasm::R_WASM_MEMORY_ADDR_LEB:
763 case wasm::R_WASM_TAG_INDEX_LEB:
764 case wasm::R_WASM_TABLE_NUMBER_LEB:
765 writePatchableU32(Stream, Value, Offset);
766 break;
767 case wasm::R_WASM_MEMORY_ADDR_LEB64:
768 writePatchableU64(Stream, Value, Offset);
769 break;
770 case wasm::R_WASM_TABLE_INDEX_I32:
771 case wasm::R_WASM_MEMORY_ADDR_I32:
772 case wasm::R_WASM_FUNCTION_OFFSET_I32:
773 case wasm::R_WASM_FUNCTION_INDEX_I32:
774 case wasm::R_WASM_SECTION_OFFSET_I32:
775 case wasm::R_WASM_GLOBAL_INDEX_I32:
776 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
777 patchI32(Stream, Value, Offset);
778 break;
779 case wasm::R_WASM_TABLE_INDEX_I64:
780 case wasm::R_WASM_MEMORY_ADDR_I64:
781 case wasm::R_WASM_FUNCTION_OFFSET_I64:
782 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I64:
783 patchI64(Stream, Value, Offset);
784 break;
785 case wasm::R_WASM_TABLE_INDEX_SLEB:
786 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
787 case wasm::R_WASM_MEMORY_ADDR_SLEB:
788 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
789 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
790 writePatchableS32(Stream, Value, Offset);
791 break;
792 case wasm::R_WASM_TABLE_INDEX_SLEB64:
793 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
794 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
795 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
796 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
797 writePatchableS64(Stream, Value, Offset);
798 break;
799 default:
800 llvm_unreachable("invalid relocation type");
801 }
802 }
803}
804
805void WasmObjectWriter::writeTypeSection(
807 if (Signatures.empty())
808 return;
809
810 SectionBookkeeping Section;
811 startSection(Section, wasm::WASM_SEC_TYPE);
812
813 encodeULEB128(Signatures.size(), W->OS);
814
815 for (const wasm::WasmSignature &Sig : Signatures) {
816 W->OS << char(wasm::WASM_TYPE_FUNC);
817 encodeULEB128(Sig.Params.size(), W->OS);
818 for (wasm::ValType Ty : Sig.Params)
819 writeValueType(Ty);
820 encodeULEB128(Sig.Returns.size(), W->OS);
821 for (wasm::ValType Ty : Sig.Returns)
822 writeValueType(Ty);
823 }
824
825 endSection(Section);
826}
827
828void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
829 uint64_t DataSize,
830 uint32_t NumElements) {
831 if (Imports.empty())
832 return;
833
834 uint64_t NumPages =
836
837 SectionBookkeeping Section;
838 startSection(Section, wasm::WASM_SEC_IMPORT);
839
840 encodeULEB128(Imports.size(), W->OS);
841 for (const wasm::WasmImport &Import : Imports) {
842 writeString(Import.Module);
843 writeString(Import.Field);
844 W->OS << char(Import.Kind);
845
846 switch (Import.Kind) {
848 encodeULEB128(Import.SigIndex, W->OS);
849 break;
851 W->OS << char(Import.Global.Type);
852 W->OS << char(Import.Global.Mutable ? 1 : 0);
853 break;
855 encodeULEB128(Import.Memory.Flags, W->OS);
856 encodeULEB128(NumPages, W->OS); // initial
857 break;
859 W->OS << char(Import.Table.ElemType);
860 encodeULEB128(Import.Table.Limits.Flags, W->OS);
861 encodeULEB128(NumElements, W->OS); // initial
862 break;
864 W->OS << char(0); // Reserved 'attribute' field
865 encodeULEB128(Import.SigIndex, W->OS);
866 break;
867 default:
868 llvm_unreachable("unsupported import kind");
869 }
870 }
871
872 endSection(Section);
873}
874
875void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
876 if (Functions.empty())
877 return;
878
879 SectionBookkeeping Section;
880 startSection(Section, wasm::WASM_SEC_FUNCTION);
881
882 encodeULEB128(Functions.size(), W->OS);
883 for (const WasmFunction &Func : Functions)
884 encodeULEB128(Func.SigIndex, W->OS);
885
886 endSection(Section);
887}
888
889void WasmObjectWriter::writeTagSection(ArrayRef<uint32_t> TagTypes) {
890 if (TagTypes.empty())
891 return;
892
893 SectionBookkeeping Section;
894 startSection(Section, wasm::WASM_SEC_TAG);
895
896 encodeULEB128(TagTypes.size(), W->OS);
897 for (uint32_t Index : TagTypes) {
898 W->OS << char(0); // Reserved 'attribute' field
899 encodeULEB128(Index, W->OS);
900 }
901
902 endSection(Section);
903}
904
905void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) {
906 if (Globals.empty())
907 return;
908
909 SectionBookkeeping Section;
910 startSection(Section, wasm::WASM_SEC_GLOBAL);
911
912 encodeULEB128(Globals.size(), W->OS);
913 for (const wasm::WasmGlobal &Global : Globals) {
914 encodeULEB128(Global.Type.Type, W->OS);
915 W->OS << char(Global.Type.Mutable);
916 if (Global.InitExpr.Extended) {
917 llvm_unreachable("extected init expressions not supported");
918 } else {
919 W->OS << char(Global.InitExpr.Inst.Opcode);
920 switch (Global.Type.Type) {
922 encodeSLEB128(0, W->OS);
923 break;
925 encodeSLEB128(0, W->OS);
926 break;
928 writeI32(0);
929 break;
931 writeI64(0);
932 break;
934 writeValueType(wasm::ValType::EXTERNREF);
935 break;
936 default:
937 llvm_unreachable("unexpected type");
938 }
939 }
940 W->OS << char(wasm::WASM_OPCODE_END);
941 }
942
943 endSection(Section);
944}
945
946void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) {
947 if (Tables.empty())
948 return;
949
950 SectionBookkeeping Section;
951 startSection(Section, wasm::WASM_SEC_TABLE);
952
953 encodeULEB128(Tables.size(), W->OS);
954 for (const wasm::WasmTable &Table : Tables) {
955 assert(Table.Type.ElemType != wasm::ValType::OTHERREF &&
956 "Cannot encode general ref-typed tables");
957 encodeULEB128((uint32_t)Table.Type.ElemType, W->OS);
958 encodeULEB128(Table.Type.Limits.Flags, W->OS);
959 encodeULEB128(Table.Type.Limits.Minimum, W->OS);
960 if (Table.Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
961 encodeULEB128(Table.Type.Limits.Maximum, W->OS);
962 }
963 endSection(Section);
964}
965
966void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
967 if (Exports.empty())
968 return;
969
970 SectionBookkeeping Section;
971 startSection(Section, wasm::WASM_SEC_EXPORT);
972
973 encodeULEB128(Exports.size(), W->OS);
974 for (const wasm::WasmExport &Export : Exports) {
975 writeString(Export.Name);
976 W->OS << char(Export.Kind);
977 encodeULEB128(Export.Index, W->OS);
978 }
979
980 endSection(Section);
981}
982
983void WasmObjectWriter::writeElemSection(
984 const MCSymbolWasm *IndirectFunctionTable, ArrayRef<uint32_t> TableElems) {
985 if (TableElems.empty())
986 return;
987
988 assert(IndirectFunctionTable);
989
990 SectionBookkeeping Section;
991 startSection(Section, wasm::WASM_SEC_ELEM);
992
993 encodeULEB128(1, W->OS); // number of "segments"
994
995 assert(WasmIndices.contains(IndirectFunctionTable));
996 uint32_t TableNumber = WasmIndices.find(IndirectFunctionTable)->second;
997 uint32_t Flags = 0;
998 if (TableNumber)
1000 encodeULEB128(Flags, W->OS);
1002 encodeULEB128(TableNumber, W->OS); // the table number
1003
1004 // init expr for starting offset
1007 encodeSLEB128(InitialTableOffset, W->OS);
1008 W->OS << char(wasm::WASM_OPCODE_END);
1009
1011 // We only write active function table initializers, for which the elem kind
1012 // is specified to be written as 0x00 and interpreted to mean "funcref".
1013 const uint8_t ElemKind = 0;
1014 W->OS << ElemKind;
1015 }
1016
1017 encodeULEB128(TableElems.size(), W->OS);
1018 for (uint32_t Elem : TableElems)
1019 encodeULEB128(Elem, W->OS);
1020
1021 endSection(Section);
1022}
1023
1024void WasmObjectWriter::writeDataCountSection() {
1025 if (DataSegments.empty())
1026 return;
1027
1028 SectionBookkeeping Section;
1029 startSection(Section, wasm::WASM_SEC_DATACOUNT);
1030 encodeULEB128(DataSegments.size(), W->OS);
1031 endSection(Section);
1032}
1033
1034uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
1035 ArrayRef<WasmFunction> Functions) {
1036 if (Functions.empty())
1037 return 0;
1038
1039 SectionBookkeeping Section;
1040 startSection(Section, wasm::WASM_SEC_CODE);
1041
1042 encodeULEB128(Functions.size(), W->OS);
1043
1044 for (const WasmFunction &Func : Functions) {
1045 auto *FuncSection = static_cast<MCSectionWasm *>(Func.Section);
1046
1047 int64_t Size = Asm.getSectionAddressSize(*FuncSection);
1048 encodeULEB128(Size, W->OS);
1049 FuncSection->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
1050 Asm.writeSectionData(W->OS, FuncSection);
1051 }
1052
1053 // Apply fixups.
1054 applyRelocations(CodeRelocations, Section.ContentsOffset, Asm);
1055
1056 endSection(Section);
1057 return Section.Index;
1058}
1059
1060uint32_t WasmObjectWriter::writeDataSection(const MCAssembler &Asm) {
1061 if (DataSegments.empty())
1062 return 0;
1063
1064 SectionBookkeeping Section;
1065 startSection(Section, wasm::WASM_SEC_DATA);
1066
1067 encodeULEB128(DataSegments.size(), W->OS); // count
1068
1069 for (const WasmDataSegment &Segment : DataSegments) {
1070 encodeULEB128(Segment.InitFlags, W->OS); // flags
1071 if (Segment.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1072 encodeULEB128(0, W->OS); // memory index
1073 if ((Segment.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1076 encodeSLEB128(Segment.Offset, W->OS); // offset
1077 W->OS << char(wasm::WASM_OPCODE_END);
1078 }
1079 encodeULEB128(Segment.Data.size(), W->OS); // size
1080 Segment.Section->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
1081 W->OS << Segment.Data; // data
1082 }
1083
1084 // Apply fixups.
1085 applyRelocations(DataRelocations, Section.ContentsOffset, Asm);
1086
1087 endSection(Section);
1088 return Section.Index;
1089}
1090
1091void WasmObjectWriter::writeRelocSection(
1092 uint32_t SectionIndex, StringRef Name,
1093 std::vector<WasmRelocationEntry> &Relocs) {
1094 // See: https://github.com/WebAssembly/tool-conventions/blob/main/Linking.md
1095 // for descriptions of the reloc sections.
1096
1097 if (Relocs.empty())
1098 return;
1099
1100 // First, ensure the relocations are sorted in offset order. In general they
1101 // should already be sorted since `recordRelocation` is called in offset
1102 // order, but for the code section we combine many MC sections into single
1103 // wasm section, and this order is determined by the order of Asm.Symbols()
1104 // not the sections order.
1106 Relocs, [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) {
1107 return (A.Offset + A.FixupSection->getSectionOffset()) <
1108 (B.Offset + B.FixupSection->getSectionOffset());
1109 });
1110
1111 SectionBookkeeping Section;
1112 startCustomSection(Section, std::string("reloc.") + Name.str());
1113
1114 encodeULEB128(SectionIndex, W->OS);
1115 encodeULEB128(Relocs.size(), W->OS);
1116 for (const WasmRelocationEntry &RelEntry : Relocs) {
1117 uint64_t Offset =
1118 RelEntry.Offset + RelEntry.FixupSection->getSectionOffset();
1119 uint32_t Index = getRelocationIndexValue(RelEntry);
1120
1121 W->OS << char(RelEntry.Type);
1122 encodeULEB128(Offset, W->OS);
1123 encodeULEB128(Index, W->OS);
1124 if (RelEntry.hasAddend())
1125 encodeSLEB128(RelEntry.Addend, W->OS);
1126 }
1127
1128 endSection(Section);
1129}
1130
1131void WasmObjectWriter::writeCustomRelocSections() {
1132 for (const auto &Sec : CustomSections) {
1133 auto &Relocations = CustomSectionsRelocations[Sec.Section];
1134 writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations);
1135 }
1136}
1137
1138void WasmObjectWriter::writeLinkingMetaDataSection(
1140 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
1141 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
1142 SectionBookkeeping Section;
1143 startCustomSection(Section, "linking");
1145
1146 SectionBookkeeping SubSection;
1147 if (SymbolInfos.size() != 0) {
1148 startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
1149 encodeULEB128(SymbolInfos.size(), W->OS);
1150 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
1151 encodeULEB128(Sym.Kind, W->OS);
1152 encodeULEB128(Sym.Flags, W->OS);
1153 switch (Sym.Kind) {
1158 encodeULEB128(Sym.ElementIndex, W->OS);
1159 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 ||
1160 (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
1161 writeString(Sym.Name);
1162 break;
1164 writeString(Sym.Name);
1165 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
1166 encodeULEB128(Sym.DataRef.Segment, W->OS);
1167 encodeULEB128(Sym.DataRef.Offset, W->OS);
1168 encodeULEB128(Sym.DataRef.Size, W->OS);
1169 }
1170 break;
1172 const uint32_t SectionIndex =
1173 CustomSections[Sym.ElementIndex].OutputIndex;
1174 encodeULEB128(SectionIndex, W->OS);
1175 break;
1176 }
1177 default:
1178 llvm_unreachable("unexpected kind");
1179 }
1180 }
1181 endSection(SubSection);
1182 }
1183
1184 if (DataSegments.size()) {
1185 startSection(SubSection, wasm::WASM_SEGMENT_INFO);
1186 encodeULEB128(DataSegments.size(), W->OS);
1187 for (const WasmDataSegment &Segment : DataSegments) {
1188 writeString(Segment.Name);
1189 encodeULEB128(Segment.Alignment, W->OS);
1190 encodeULEB128(Segment.LinkingFlags, W->OS);
1191 }
1192 endSection(SubSection);
1193 }
1194
1195 if (!InitFuncs.empty()) {
1196 startSection(SubSection, wasm::WASM_INIT_FUNCS);
1197 encodeULEB128(InitFuncs.size(), W->OS);
1198 for (auto &StartFunc : InitFuncs) {
1199 encodeULEB128(StartFunc.first, W->OS); // priority
1200 encodeULEB128(StartFunc.second, W->OS); // function index
1201 }
1202 endSection(SubSection);
1203 }
1204
1205 if (Comdats.size()) {
1206 startSection(SubSection, wasm::WASM_COMDAT_INFO);
1207 encodeULEB128(Comdats.size(), W->OS);
1208 for (const auto &C : Comdats) {
1209 writeString(C.first);
1210 encodeULEB128(0, W->OS); // flags for future use
1211 encodeULEB128(C.second.size(), W->OS);
1212 for (const WasmComdatEntry &Entry : C.second) {
1213 encodeULEB128(Entry.Kind, W->OS);
1214 encodeULEB128(Entry.Index, W->OS);
1215 }
1216 }
1217 endSection(SubSection);
1218 }
1219
1220 endSection(Section);
1221}
1222
1223void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection,
1224 const MCAssembler &Asm) {
1225 SectionBookkeeping Section;
1226 auto *Sec = CustomSection.Section;
1227 startCustomSection(Section, CustomSection.Name);
1228
1229 Sec->setSectionOffset(W->OS.tell() - Section.ContentsOffset);
1230 Asm.writeSectionData(W->OS, Sec);
1231
1232 CustomSection.OutputContentsOffset = Section.ContentsOffset;
1233 CustomSection.OutputIndex = Section.Index;
1234
1235 endSection(Section);
1236
1237 // Apply fixups.
1238 auto &Relocations = CustomSectionsRelocations[CustomSection.Section];
1239 applyRelocations(Relocations, CustomSection.OutputContentsOffset, Asm);
1240}
1241
1242uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
1243 assert(Symbol.isFunction());
1244 assert(TypeIndices.contains(&Symbol));
1245 return TypeIndices[&Symbol];
1246}
1247
1248uint32_t WasmObjectWriter::getTagType(const MCSymbolWasm &Symbol) {
1249 assert(Symbol.isTag());
1250 assert(TypeIndices.contains(&Symbol));
1251 return TypeIndices[&Symbol];
1252}
1253
1254void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
1255 assert(Symbol.isFunction());
1256
1257 wasm::WasmSignature S;
1258
1259 if (auto *Sig = Symbol.getSignature()) {
1260 S.Returns = Sig->Returns;
1261 S.Params = Sig->Params;
1262 }
1263
1264 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
1265 if (Pair.second)
1266 Signatures.push_back(S);
1267 TypeIndices[&Symbol] = Pair.first->second;
1268
1269 LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
1270 << " new:" << Pair.second << "\n");
1271 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
1272}
1273
1274void WasmObjectWriter::registerTagType(const MCSymbolWasm &Symbol) {
1275 assert(Symbol.isTag());
1276
1277 // TODO Currently we don't generate imported exceptions, but if we do, we
1278 // should have a way of infering types of imported exceptions.
1279 wasm::WasmSignature S;
1280 if (auto *Sig = Symbol.getSignature()) {
1281 S.Returns = Sig->Returns;
1282 S.Params = Sig->Params;
1283 }
1284
1285 auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
1286 if (Pair.second)
1287 Signatures.push_back(S);
1288 TypeIndices[&Symbol] = Pair.first->second;
1289
1290 LLVM_DEBUG(dbgs() << "registerTagType: " << Symbol << " new:" << Pair.second
1291 << "\n");
1292 LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
1293}
1294
1295static bool isInSymtab(const MCSymbolWasm &Sym) {
1296 if (Sym.isUsedInReloc() || Sym.isUsedInInitArray())
1297 return true;
1298
1299 if (Sym.isComdat() && !Sym.isDefined())
1300 return false;
1301
1302 if (Sym.isTemporary())
1303 return false;
1304
1305 if (Sym.isSection())
1306 return false;
1307
1308 if (Sym.omitFromLinkingSection())
1309 return false;
1310
1311 return true;
1312}
1313
1314static bool isSectionReferenced(MCAssembler &Asm, MCSectionWasm &Section) {
1315 StringRef SectionName = Section.getName();
1316
1317 for (const MCSymbol &S : Asm.symbols()) {
1318 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1319 if (WS.isData() && WS.isInSection()) {
1320 auto &RefSection = static_cast<MCSectionWasm &>(WS.getSection());
1321 if (RefSection.getName() == SectionName) {
1322 return true;
1323 }
1324 }
1325 }
1326
1327 return false;
1328}
1329
1330void WasmObjectWriter::prepareImports(
1331 SmallVectorImpl<wasm::WasmImport> &Imports, MCAssembler &Asm) {
1332 // For now, always emit the memory import, since loads and stores are not
1333 // valid without it. In the future, we could perhaps be more clever and omit
1334 // it if there are no loads or stores.
1335 wasm::WasmImport MemImport;
1336 MemImport.Module = "env";
1337 MemImport.Field = "__linear_memory";
1338 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
1341 Imports.push_back(MemImport);
1342
1343 // Populate SignatureIndices, and Imports and WasmIndices for undefined
1344 // symbols. This must be done before populating WasmIndices for defined
1345 // symbols.
1346 for (const MCSymbol &S : Asm.symbols()) {
1347 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1348
1349 // Register types for all functions, including those with private linkage
1350 // (because wasm always needs a type signature).
1351 if (WS.isFunction()) {
1352 auto *BS = static_cast<const MCSymbolWasm *>(Asm.getBaseSymbol(S));
1353 if (!BS)
1354 report_fatal_error(Twine(S.getName()) +
1355 ": absolute addressing not supported!");
1356 registerFunctionType(*BS);
1357 }
1358
1359 if (WS.isTag())
1360 registerTagType(WS);
1361
1362 if (WS.isTemporary())
1363 continue;
1364
1365 // If the symbol is not defined in this translation unit, import it.
1366 if (!WS.isDefined() && !WS.isComdat()) {
1367 if (WS.isFunction()) {
1368 wasm::WasmImport Import;
1369 Import.Module = WS.getImportModule();
1370 Import.Field = WS.getImportName();
1372 Import.SigIndex = getFunctionType(WS);
1373 Imports.push_back(Import);
1374 assert(!WasmIndices.contains(&WS));
1375 WasmIndices[&WS] = NumFunctionImports++;
1376 } else if (WS.isGlobal()) {
1377 if (WS.isWeak())
1378 report_fatal_error("undefined global symbol cannot be weak");
1379
1380 wasm::WasmImport Import;
1381 Import.Field = WS.getImportName();
1383 Import.Module = WS.getImportModule();
1384 Import.Global = WS.getGlobalType();
1385 Imports.push_back(Import);
1386 assert(!WasmIndices.contains(&WS));
1387 WasmIndices[&WS] = NumGlobalImports++;
1388 } else if (WS.isTag()) {
1389 if (WS.isWeak())
1390 report_fatal_error("undefined tag symbol cannot be weak");
1391
1392 wasm::WasmImport Import;
1393 Import.Module = WS.getImportModule();
1394 Import.Field = WS.getImportName();
1396 Import.SigIndex = getTagType(WS);
1397 Imports.push_back(Import);
1398 assert(!WasmIndices.contains(&WS));
1399 WasmIndices[&WS] = NumTagImports++;
1400 } else if (WS.isTable()) {
1401 if (WS.isWeak())
1402 report_fatal_error("undefined table symbol cannot be weak");
1403
1404 wasm::WasmImport Import;
1405 Import.Module = WS.getImportModule();
1406 Import.Field = WS.getImportName();
1408 Import.Table = WS.getTableType();
1409 Imports.push_back(Import);
1410 assert(!WasmIndices.contains(&WS));
1411 WasmIndices[&WS] = NumTableImports++;
1412 }
1413 }
1414 }
1415
1416 // Add imports for GOT globals
1417 for (const MCSymbol &S : Asm.symbols()) {
1418 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1419 if (WS.isUsedInGOT()) {
1420 wasm::WasmImport Import;
1421 if (WS.isFunction())
1422 Import.Module = "GOT.func";
1423 else
1424 Import.Module = "GOT.mem";
1425 Import.Field = WS.getName();
1427 Import.Global = {wasm::WASM_TYPE_I32, true};
1428 Imports.push_back(Import);
1429 assert(!GOTIndices.contains(&WS));
1430 GOTIndices[&WS] = NumGlobalImports++;
1431 }
1432 }
1433}
1434
1435uint64_t WasmObjectWriter::writeObject() {
1436 support::endian::Writer MainWriter(*OS, llvm::endianness::little);
1437 W = &MainWriter;
1438 if (IsSplitDwarf) {
1439 uint64_t TotalSize = writeOneObject(*Asm, DwoMode::NonDwoOnly);
1440 assert(DwoOS);
1441 support::endian::Writer DwoWriter(*DwoOS, llvm::endianness::little);
1442 W = &DwoWriter;
1443 return TotalSize + writeOneObject(*Asm, DwoMode::DwoOnly);
1444 } else {
1445 return writeOneObject(*Asm, DwoMode::AllSections);
1446 }
1447}
1448
1449uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
1450 DwoMode Mode) {
1451 uint64_t StartOffset = W->OS.tell();
1452 SectionCount = 0;
1453 CustomSections.clear();
1454
1455 LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
1456
1457 // Collect information from the available symbols.
1459 SmallVector<uint32_t, 4> TableElems;
1462 SmallVector<uint32_t, 2> TagTypes;
1467 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
1468 uint64_t DataSize = 0;
1469 if (Mode != DwoMode::DwoOnly)
1470 prepareImports(Imports, Asm);
1471
1472 // Populate DataSegments and CustomSections, which must be done before
1473 // populating DataLocations.
1474 for (MCSection &Sec : Asm) {
1475 auto &Section = static_cast<MCSectionWasm &>(Sec);
1476 StringRef SectionName = Section.getName();
1477
1478 if (Mode == DwoMode::NonDwoOnly && isDwoSection(Sec))
1479 continue;
1480 if (Mode == DwoMode::DwoOnly && !isDwoSection(Sec))
1481 continue;
1482
1483 LLVM_DEBUG(dbgs() << "Processing Section " << SectionName << " group "
1484 << Section.getGroup() << "\n";);
1485
1486 // .init_array sections are handled specially elsewhere, include them in
1487 // data segments if and only if referenced by a symbol.
1488 if (SectionName.starts_with(".init_array") &&
1489 !isSectionReferenced(Asm, Section))
1490 continue;
1491
1492 // Code is handled separately
1493 if (Section.isText())
1494 continue;
1495
1496 if (Section.isWasmData()) {
1497 uint32_t SegmentIndex = DataSegments.size();
1498 DataSize = alignTo(DataSize, Section.getAlign());
1499 DataSegments.emplace_back();
1500 WasmDataSegment &Segment = DataSegments.back();
1501 Segment.Name = SectionName;
1502 Segment.InitFlags = Section.getPassive()
1504 : 0;
1505 Segment.Offset = DataSize;
1506 Segment.Section = &Section;
1507 addData(Segment.Data, Section);
1508 Segment.Alignment = Log2(Section.getAlign());
1509 Segment.LinkingFlags = Section.getSegmentFlags();
1510 DataSize += Segment.Data.size();
1511 Section.setSegmentIndex(SegmentIndex);
1512
1513 if (const MCSymbolWasm *C = Section.getGroup()) {
1514 Comdats[C->getName()].emplace_back(
1515 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
1516 }
1517 } else {
1518 // Create custom sections
1519 assert(Section.isMetadata());
1520
1521 StringRef Name = SectionName;
1522
1523 // For user-defined custom sections, strip the prefix
1524 Name.consume_front(".custom_section.");
1525
1526 auto *Begin = static_cast<MCSymbolWasm *>(Sec.getBeginSymbol());
1527 if (Begin) {
1528 assert(!WasmIndices.contains(Begin));
1529 WasmIndices[Begin] = CustomSections.size();
1530 }
1531
1532 // Separate out the producers and target features sections
1533 if (Name == "producers") {
1534 ProducersSection = std::make_unique<WasmCustomSection>(Name, &Section);
1535 continue;
1536 }
1537 if (Name == "target_features") {
1538 TargetFeaturesSection =
1539 std::make_unique<WasmCustomSection>(Name, &Section);
1540 continue;
1541 }
1542
1543 // Custom sections can also belong to COMDAT groups. In this case the
1544 // decriptor's "index" field is the section index (in the final object
1545 // file), but that is not known until after layout, so it must be fixed up
1546 // later
1547 if (const MCSymbolWasm *C = Section.getGroup()) {
1548 Comdats[C->getName()].emplace_back(
1549 WasmComdatEntry{wasm::WASM_COMDAT_SECTION,
1550 static_cast<uint32_t>(CustomSections.size())});
1551 }
1552
1553 CustomSections.emplace_back(Name, &Section);
1554 }
1555 }
1556
1557 if (Mode != DwoMode::DwoOnly) {
1558 // Populate WasmIndices and DataLocations for defined symbols.
1559 for (const MCSymbol &S : Asm.symbols()) {
1560 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1561 // or used in relocations.
1562 if (S.isTemporary() && S.getName().empty())
1563 continue;
1564
1565 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1566 LLVM_DEBUG(
1567 dbgs() << "MCSymbol: "
1568 << toString(WS.getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA))
1569 << " '" << S << "'"
1570 << " isDefined=" << S.isDefined() << " isExternal="
1571 << WS.isExternal() << " isTemporary=" << S.isTemporary()
1572 << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden()
1573 << " isVariable=" << WS.isVariable() << "\n");
1574
1575 if (WS.isVariable())
1576 continue;
1577 if (WS.isComdat() && !WS.isDefined())
1578 continue;
1579
1580 if (WS.isFunction()) {
1581 unsigned Index;
1582 if (WS.isDefined()) {
1583 if (WS.getOffset() != 0)
1585 "function sections must contain one function each");
1586
1587 // A definition. Write out the function body.
1588 Index = NumFunctionImports + Functions.size();
1589 WasmFunction Func;
1590 Func.SigIndex = getFunctionType(WS);
1591 Func.Section = &WS.getSection();
1592 assert(!WasmIndices.contains(&WS));
1593 WasmIndices[&WS] = Index;
1594 Functions.push_back(Func);
1595
1596 auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
1597 if (const MCSymbolWasm *C = Section.getGroup()) {
1598 Comdats[C->getName()].emplace_back(
1599 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
1600 }
1601
1602 if (WS.hasExportName()) {
1603 wasm::WasmExport Export;
1604 Export.Name = WS.getExportName();
1606 Export.Index = Index;
1607 Exports.push_back(Export);
1608 }
1609 } else {
1610 // An import; the index was assigned above.
1611 Index = WasmIndices.find(&WS)->second;
1612 }
1613
1614 LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
1615
1616 } else if (WS.isData()) {
1617 if (!isInSymtab(WS))
1618 continue;
1619
1620 if (!WS.isDefined()) {
1621 LLVM_DEBUG(dbgs() << " -> segment index: -1"
1622 << "\n");
1623 continue;
1624 }
1625
1626 if (!WS.getSize())
1627 report_fatal_error("data symbols must have a size set with .size: " +
1628 WS.getName());
1629
1630 int64_t Size = 0;
1631 if (!WS.getSize()->evaluateAsAbsolute(Size, Asm))
1632 report_fatal_error(".size expression must be evaluatable");
1633
1634 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
1635 if (!DataSection.isWasmData())
1636 report_fatal_error("data symbols must live in a data section: " +
1637 WS.getName());
1638
1639 // For each data symbol, export it in the symtab as a reference to the
1640 // corresponding Wasm data segment.
1641 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1642 DataSection.getSegmentIndex(), Asm.getSymbolOffset(WS),
1643 static_cast<uint64_t>(Size)};
1644 assert(!DataLocations.contains(&WS));
1645 DataLocations[&WS] = Ref;
1646 LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
1647
1648 } else if (WS.isGlobal()) {
1649 // A "true" Wasm global (currently just __stack_pointer)
1650 if (WS.isDefined()) {
1651 wasm::WasmGlobal Global;
1652 Global.Type = WS.getGlobalType();
1653 Global.Index = NumGlobalImports + Globals.size();
1654 Global.InitExpr.Extended = false;
1655 switch (Global.Type.Type) {
1657 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1658 break;
1660 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_I64_CONST;
1661 break;
1663 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_F32_CONST;
1664 break;
1666 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_F64_CONST;
1667 break;
1669 Global.InitExpr.Inst.Opcode = wasm::WASM_OPCODE_REF_NULL;
1670 break;
1671 default:
1672 llvm_unreachable("unexpected type");
1673 }
1674 assert(!WasmIndices.contains(&WS));
1675 WasmIndices[&WS] = Global.Index;
1676 Globals.push_back(Global);
1677 } else {
1678 // An import; the index was assigned above
1679 LLVM_DEBUG(dbgs() << " -> global index: "
1680 << WasmIndices.find(&WS)->second << "\n");
1681 }
1682 } else if (WS.isTable()) {
1683 if (WS.isDefined()) {
1684 wasm::WasmTable Table;
1685 Table.Index = NumTableImports + Tables.size();
1686 Table.Type = WS.getTableType();
1687 assert(!WasmIndices.contains(&WS));
1688 WasmIndices[&WS] = Table.Index;
1689 Tables.push_back(Table);
1690 }
1691 LLVM_DEBUG(dbgs() << " -> table index: "
1692 << WasmIndices.find(&WS)->second << "\n");
1693 } else if (WS.isTag()) {
1694 // C++ exception symbol (__cpp_exception) or longjmp symbol
1695 // (__c_longjmp)
1696 unsigned Index;
1697 if (WS.isDefined()) {
1698 Index = NumTagImports + TagTypes.size();
1699 uint32_t SigIndex = getTagType(WS);
1700 assert(!WasmIndices.contains(&WS));
1701 WasmIndices[&WS] = Index;
1702 TagTypes.push_back(SigIndex);
1703 } else {
1704 // An import; the index was assigned above.
1705 assert(WasmIndices.contains(&WS));
1706 }
1707 LLVM_DEBUG(dbgs() << " -> tag index: " << WasmIndices.find(&WS)->second
1708 << "\n");
1709
1710 } else {
1711 assert(WS.isSection());
1712 }
1713 }
1714
1715 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1716 // process these in a separate pass because we need to have processed the
1717 // target of the alias before the alias itself and the symbols are not
1718 // necessarily ordered in this way.
1719 for (const MCSymbol &S : Asm.symbols()) {
1720 if (!S.isVariable())
1721 continue;
1722
1723 assert(S.isDefined());
1724
1725 const auto *BS = Asm.getBaseSymbol(S);
1726 if (!BS)
1727 report_fatal_error(Twine(S.getName()) +
1728 ": absolute addressing not supported!");
1729 const MCSymbolWasm *Base = static_cast<const MCSymbolWasm *>(BS);
1730
1731 // Find the target symbol of this weak alias and export that index
1732 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1733 LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *Base
1734 << "'\n");
1735
1736 if (Base->isFunction()) {
1737 assert(WasmIndices.contains(Base));
1738 uint32_t WasmIndex = WasmIndices.find(Base)->second;
1739 assert(!WasmIndices.contains(&WS));
1740 WasmIndices[&WS] = WasmIndex;
1741 LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
1742 } else if (Base->isData()) {
1743 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
1744 uint64_t Offset = Asm.getSymbolOffset(S);
1745 int64_t Size = 0;
1746 // For data symbol alias we use the size of the base symbol as the
1747 // size of the alias. When an offset from the base is involved this
1748 // can result in a offset + size goes past the end of the data section
1749 // which out object format doesn't support. So we must clamp it.
1750 if (!Base->getSize()->evaluateAsAbsolute(Size, Asm))
1751 report_fatal_error(".size expression must be evaluatable");
1752 const WasmDataSegment &Segment =
1753 DataSegments[DataSection.getSegmentIndex()];
1754 Size =
1755 std::min(static_cast<uint64_t>(Size), Segment.Data.size() - Offset);
1756 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1757 DataSection.getSegmentIndex(),
1758 static_cast<uint32_t>(Asm.getSymbolOffset(S)),
1759 static_cast<uint32_t>(Size)};
1760 DataLocations[&WS] = Ref;
1761 LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
1762 } else {
1763 report_fatal_error("don't yet support global/tag aliases");
1764 }
1765 }
1766 }
1767
1768 // Finally, populate the symbol table itself, in its "natural" order.
1769 for (const MCSymbol &S : Asm.symbols()) {
1770 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1771 if (!isInSymtab(WS)) {
1772 WS.setIndex(InvalidIndex);
1773 continue;
1774 }
1775 // In bitcode generated by split-LTO-unit mode in ThinLTO, these lines can
1776 // appear:
1777 // module asm ".lto_set_conditional symbolA,symbolA.[moduleId]"
1778 // ...
1779 // (Here [moduleId] will be replaced by a real module hash ID)
1780 //
1781 // Here the original symbol (symbolA here) has been renamed to the new name
1782 // created by attaching its module ID, so the original symbol does not
1783 // appear in the bitcode anymore, and thus not in DataLocations. We should
1784 // ignore them.
1785 if (WS.isData() && WS.isDefined() && !DataLocations.contains(&WS))
1786 continue;
1787 LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
1788
1789 uint32_t Flags = 0;
1790 if (WS.isWeak())
1792 if (WS.isHidden())
1794 if (!WS.isExternal() && WS.isDefined())
1796 if (WS.isUndefined())
1798 if (WS.isNoStrip()) {
1800 if (isEmscripten()) {
1802 }
1803 }
1804 if (WS.hasImportName())
1806 if (WS.hasExportName())
1808 if (WS.isTLS())
1810
1811 wasm::WasmSymbolInfo Info;
1812 Info.Name = WS.getName();
1813 Info.Kind = WS.getType().value_or(wasm::WASM_SYMBOL_TYPE_DATA);
1814 Info.Flags = Flags;
1815 if (!WS.isData()) {
1816 assert(WasmIndices.contains(&WS));
1817 Info.ElementIndex = WasmIndices.find(&WS)->second;
1818 } else if (WS.isDefined()) {
1819 assert(DataLocations.contains(&WS));
1820 Info.DataRef = DataLocations.find(&WS)->second;
1821 }
1822 WS.setIndex(SymbolInfos.size());
1823 SymbolInfos.emplace_back(Info);
1824 }
1825
1826 {
1827 auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
1828 // Functions referenced by a relocation need to put in the table. This is
1829 // purely to make the object file's provisional values readable, and is
1830 // ignored by the linker, which re-calculates the relocations itself.
1831 if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
1832 Rel.Type != wasm::R_WASM_TABLE_INDEX_I64 &&
1833 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB &&
1834 Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB64 &&
1835 Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB &&
1836 Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB64)
1837 return;
1838 assert(Rel.Symbol->isFunction());
1839 auto *Base =
1840 static_cast<const MCSymbolWasm *>(Asm.getBaseSymbol(*Rel.Symbol));
1841 uint32_t FunctionIndex = WasmIndices.find(Base)->second;
1842 uint32_t TableIndex = TableElems.size() + InitialTableOffset;
1843 if (TableIndices.try_emplace(Base, TableIndex).second) {
1844 LLVM_DEBUG(dbgs() << " -> adding " << Base->getName()
1845 << " to table: " << TableIndex << "\n");
1846 TableElems.push_back(FunctionIndex);
1847 registerFunctionType(*Base);
1848 }
1849 };
1850
1851 for (const WasmRelocationEntry &RelEntry : CodeRelocations)
1852 HandleReloc(RelEntry);
1853 for (const WasmRelocationEntry &RelEntry : DataRelocations)
1854 HandleReloc(RelEntry);
1855 }
1856
1857 // Translate .init_array section contents into start functions.
1858 for (const MCSection &S : Asm) {
1859 const auto &WS = static_cast<const MCSectionWasm &>(S);
1860 if (WS.getName().starts_with(".fini_array"))
1861 report_fatal_error(".fini_array sections are unsupported");
1862 if (!WS.getName().starts_with(".init_array"))
1863 continue;
1864 auto IT = WS.begin();
1865 if (IT == WS.end())
1866 continue;
1867 for (auto *Frag = &*IT; Frag; Frag = Frag->getNext()) {
1868 if (Frag->hasInstructions() || (Frag->getKind() != MCFragment::FT_Align &&
1869 Frag->getKind() != MCFragment::FT_Data))
1870 report_fatal_error("only data supported in .init_array section");
1871
1872 uint16_t Priority = UINT16_MAX;
1873 unsigned PrefixLength = strlen(".init_array");
1874 if (WS.getName().size() > PrefixLength) {
1875 if (WS.getName()[PrefixLength] != '.')
1877 ".init_array section priority should start with '.'");
1878 if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority))
1879 report_fatal_error("invalid .init_array section priority");
1880 }
1881 assert(llvm::all_of(Frag->getContents(), [](char C) { return !C; }));
1882 for (const MCFixup &Fixup : Frag->getFixups()) {
1883 assert(Fixup.getKind() ==
1885 const MCExpr *Expr = Fixup.getValue();
1886 auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr);
1887 if (!SymRef)
1889 "fixups in .init_array should be symbol references");
1890 auto &TargetSym =
1891 static_cast<const MCSymbolWasm &>(SymRef->getSymbol());
1892 if (TargetSym.getIndex() == InvalidIndex)
1893 report_fatal_error("symbols in .init_array should exist in symtab");
1894 if (!TargetSym.isFunction())
1895 report_fatal_error("symbols in .init_array should be for functions");
1896 InitFuncs.push_back(std::make_pair(Priority, TargetSym.getIndex()));
1897 }
1898 }
1899 }
1900
1901 // Write out the Wasm header.
1902 writeHeader(Asm);
1903
1904 uint32_t CodeSectionIndex, DataSectionIndex;
1905 if (Mode != DwoMode::DwoOnly) {
1906 writeTypeSection(Signatures);
1907 writeImportSection(Imports, DataSize, TableElems.size());
1908 writeFunctionSection(Functions);
1909 writeTableSection(Tables);
1910 // Skip the "memory" section; we import the memory instead.
1911 writeTagSection(TagTypes);
1912 writeGlobalSection(Globals);
1913 writeExportSection(Exports);
1914 const MCSymbol *IndirectFunctionTable =
1915 getContext().lookupSymbol("__indirect_function_table");
1916 writeElemSection(static_cast<const MCSymbolWasm *>(IndirectFunctionTable),
1917 TableElems);
1918 writeDataCountSection();
1919
1920 CodeSectionIndex = writeCodeSection(Asm, Functions);
1921 DataSectionIndex = writeDataSection(Asm);
1922 }
1923
1924 // The Sections in the COMDAT list have placeholder indices (their index among
1925 // custom sections, rather than among all sections). Fix them up here.
1926 for (auto &Group : Comdats) {
1927 for (auto &Entry : Group.second) {
1928 if (Entry.Kind == wasm::WASM_COMDAT_SECTION) {
1929 Entry.Index += SectionCount;
1930 }
1931 }
1932 }
1933 for (auto &CustomSection : CustomSections)
1934 writeCustomSection(CustomSection, Asm);
1935
1936 if (Mode != DwoMode::DwoOnly) {
1937 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
1938
1939 writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
1940 writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
1941 }
1942 writeCustomRelocSections();
1943 if (ProducersSection)
1944 writeCustomSection(*ProducersSection, Asm);
1945 if (TargetFeaturesSection)
1946 writeCustomSection(*TargetFeaturesSection, Asm);
1947
1948 // TODO: Translate the .comment section to the output.
1949 return W->OS.tell() - StartOffset;
1950}
1951
1952std::unique_ptr<MCObjectWriter>
1953llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1954 raw_pwrite_stream &OS) {
1955 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
1956}
1957
1958std::unique_ptr<MCObjectWriter>
1959llvm::createWasmDwoObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1961 raw_pwrite_stream &DwoOS) {
1962 return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS, DwoOS);
1963}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate any type of IT block"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow complex IT blocks")))
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:663
static void writeString(raw_ostream &OS, StringRef S)
#define F(x, y, z)
Definition MD5.cpp:54
#define T
PowerPC TLS Dynamic Call Fixup
static cl::opt< RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode > Mode("regalloc-enable-advisor", cl::Hidden, cl::init(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default), cl::desc("Enable regalloc advisor mode"), cl::values(clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Default, "default", "Default"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Release, "release", "precompiled"), clEnumValN(RegAllocEvictionAdvisorAnalysisLegacy::AdvisorMode::Development, "development", "for training")))
This file contains some templates that are useful if you are working with the STL at all.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static const unsigned InvalidIndex
static bool isSectionReferenced(MCAssembler &Asm, MCSectionWasm &Section)
static void addData(SmallVectorImpl< char > &DataBytes, MCSectionWasm &DataSection)
static bool isInSymtab(const MCSymbolWasm &Sym)
static bool isDwoSection(const MCSection &Sec)
static bool is64Bit(const char *name)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
LLVM_ABI MCSymbol * lookupSymbol(const Twine &Name) const
Get the symbol for Name, or null.
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
Encode information on a single operation to perform on a byte sequence (e.g., an encoded instruction)...
Definition MCFixup.h:61
static MCFixupKind getDataKindForSize(unsigned Size)
Return the generic fixup kind for a value with the given size.
Definition MCFixup.h:110
Defines the object file and target independent interfaces used by the assembler backend to write nati...
virtual void reset()
lifetime management
This represents a section on wasm.
uint64_t getSectionOffset() const
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition MCSection.h:573
Align getAlign() const
Definition MCSection.h:657
bool isText() const
Definition MCSection.h:644
StringRef getName() const
Definition MCSection.h:643
MCSymbol * getBeginSymbol()
Definition MCSection.h:646
bool isGlobal() const
bool isSection() const
bool omitFromLinkingSection() const
bool isComdat() const
bool isUsedInInitArray() const
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
bool isDefined() const
isDefined - Check if this symbol is defined (i.e., it has an address).
Definition MCSymbol.h:233
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
uint32_t getIndex() const
Get the (implementation defined) index.
Definition MCSymbol.h:280
MCSection & getSection() const
Get the section associated with a defined, non-absolute symbol.
Definition MCSymbol.h:251
bool isTemporary() const
isTemporary - Check if this is an assembler temporary symbol.
Definition MCSymbol.h:205
bool isUsedInReloc() const
Definition MCSymbol.h:199
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
iterator insert(iterator I, T &&Elt)
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
Definition StringRef.h:270
Target - Wrapper for Target specific information.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM Value Representation.
Definition Value.h:75
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
uint64_t tell() const
tell - Return the current offset with the file.
raw_ostream & write(unsigned char C)
An abstract base class for streams implementations that also support a pwrite operation.
void pwrite(const char *Ptr, size_t Size, uint64_t Offset)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const char SectionName[]
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ Entry
Definition COFF.h:862
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
LLVM_ABI void writeHeader(support::endian::Writer &W, bool Is64Bit, uint8_t OSABI, uint8_t ABIVersion, uint16_t EMachine, uint32_t EFlags, uint64_t SHOff, uint16_t SHNum, uint16_t SHStrNdx)
Write an ELF file header (Elf32_Ehdr or Elf64_Ehdr) for an ET_REL object.
Definition ELFWriter.cpp:21
bool isRelocRelocation(MCFixupKind FixupKind)
Definition MCFixup.h:135
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:393
Context & getContext() const
Definition BasicBlock.h:99
void write64le(void *P, uint64_t V)
Definition Endian.h:478
void write32le(void *P, uint32_t V)
Definition Endian.h:475
const unsigned WASM_SYMBOL_UNDEFINED
Definition Wasm.h:256
const unsigned WASM_SYMBOL_NO_STRIP
Definition Wasm.h:259
@ WASM_TYPE_I64
Definition Wasm.h:57
@ WASM_TYPE_F64
Definition Wasm.h:59
@ WASM_TYPE_EXTERNREF
Definition Wasm.h:66
@ WASM_TYPE_FUNC
Definition Wasm.h:75
@ WASM_TYPE_I32
Definition Wasm.h:56
@ WASM_TYPE_F32
Definition Wasm.h:58
const char WasmMagic[]
Definition Wasm.h:27
const unsigned WASM_SYMBOL_TLS
Definition Wasm.h:260
const uint32_t WasmMetadataVersion
Definition Wasm.h:31
const unsigned WASM_SYMBOL_BINDING_WEAK
Definition Wasm.h:252
@ WASM_SEC_CODE
Definition Wasm.h:47
@ WASM_SEC_IMPORT
Definition Wasm.h:39
@ WASM_SEC_EXPORT
Definition Wasm.h:44
@ WASM_SEC_DATACOUNT
Definition Wasm.h:49
@ WASM_SEC_CUSTOM
Definition Wasm.h:37
@ WASM_SEC_FUNCTION
Definition Wasm.h:40
@ WASM_SEC_ELEM
Definition Wasm.h:46
@ WASM_SEC_TABLE
Definition Wasm.h:41
@ WASM_SEC_TYPE
Definition Wasm.h:38
@ WASM_SEC_TAG
Definition Wasm.h:50
@ WASM_SEC_GLOBAL
Definition Wasm.h:43
@ WASM_SEC_DATA
Definition Wasm.h:48
const unsigned WASM_SYMBOL_BINDING_LOCAL
Definition Wasm.h:253
@ WASM_LIMITS_FLAG_HAS_MAX
Definition Wasm.h:168
@ WASM_LIMITS_FLAG_IS_64
Definition Wasm.h:170
@ WASM_LIMITS_FLAG_NONE
Definition Wasm.h:167
@ WASM_SYMBOL_TYPE_GLOBAL
Definition Wasm.h:231
@ WASM_SYMBOL_TYPE_DATA
Definition Wasm.h:230
@ WASM_SYMBOL_TYPE_TAG
Definition Wasm.h:233
@ WASM_SYMBOL_TYPE_TABLE
Definition Wasm.h:234
@ WASM_SYMBOL_TYPE_SECTION
Definition Wasm.h:232
@ WASM_SYMBOL_TYPE_FUNCTION
Definition Wasm.h:229
const uint32_t WasmVersion
Definition Wasm.h:29
const unsigned WASM_SYMBOL_EXPORTED
Definition Wasm.h:257
@ WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER
Definition Wasm.h:182
@ WASM_DATA_SEGMENT_IS_PASSIVE
Definition Wasm.h:175
@ WASM_DATA_SEGMENT_HAS_MEMINDEX
Definition Wasm.h:176
LLVM_ABI bool relocTypeHasAddend(uint32_t type)
Definition Wasm.cpp:66
@ WASM_EXTERNAL_TABLE
Definition Wasm.h:96
@ WASM_EXTERNAL_FUNCTION
Definition Wasm.h:95
@ WASM_EXTERNAL_TAG
Definition Wasm.h:99
@ WASM_EXTERNAL_MEMORY
Definition Wasm.h:97
@ WASM_EXTERNAL_GLOBAL
Definition Wasm.h:98
@ WASM_INIT_FUNCS
Definition Wasm.h:205
@ WASM_COMDAT_INFO
Definition Wasm.h:206
@ WASM_SEGMENT_INFO
Definition Wasm.h:204
@ WASM_SYMBOL_TABLE
Definition Wasm.h:207
@ WASM_COMDAT_SECTION
Definition Wasm.h:224
@ WASM_COMDAT_FUNCTION
Definition Wasm.h:222
@ WASM_COMDAT_DATA
Definition Wasm.h:221
@ WASM_OPCODE_F64_CONST
Definition Wasm.h:116
@ WASM_OPCODE_END
Definition Wasm.h:104
@ WASM_OPCODE_REF_NULL
Definition Wasm.h:123
@ WASM_OPCODE_F32_CONST
Definition Wasm.h:115
@ WASM_OPCODE_I64_CONST
Definition Wasm.h:114
@ WASM_OPCODE_I32_CONST
Definition Wasm.h:113
const uint32_t WasmDefaultPageSize
Definition Wasm.h:34
const unsigned WASM_SYMBOL_EXPLICIT_NAME
Definition Wasm.h:258
const unsigned WASM_SYMBOL_VISIBILITY_HIDDEN
Definition Wasm.h:255
const unsigned WASM_ELEM_SEGMENT_MASK_HAS_ELEM_DESC
Definition Wasm.h:185
LLVM_ABI llvm::StringRef relocTypetoString(uint32_t type)
Definition Wasm.cpp:29
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
@ Offset
Definition DWP.cpp:558
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
void stable_sort(R &&Range)
Definition STLExtras.h:2115
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1738
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Export
Export information to summary.
Definition IPO.h:57
@ Import
Import information from summary.
Definition IPO.h:56
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2207
FunctionAddr VTableAddr uintptr_t uintptr_t DataSize
Definition InstrProf.h:299
LLVM_ABI std::unique_ptr< MCObjectWriter > createWasmObjectWriter(std::unique_ptr< MCWasmObjectTargetWriter > MOTW, raw_pwrite_stream &OS)
Construct a new Wasm writer instance.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
uint64_t offsetToAlignment(uint64_t Value, Align Alignment)
Returns the offset to the next integer (mod 2**64) that is greater than or equal to Value and is a mu...
Definition Alignment.h:186
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Global
Append to llvm.global_dtors.
@ Ref
The access may reference the value stored in memory.
Definition ModRef.h:32
@ FirstLiteralRelocationKind
Definition MCFixup.h:29
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a SLEB128 value to an output stream.
Definition LEB128.h:24
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition LEB128.h:79
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:197
LLVM_ABI std::unique_ptr< MCObjectWriter > createWasmDwoObjectWriter(std::unique_ptr< MCWasmObjectTargetWriter > MOTW, raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS)
Adapter to write values to a stream in a particular byte order.
void write(ArrayRef< value_type > Val)
WasmLimits Memory
Definition Wasm.h:396
StringRef Field
Definition Wasm.h:390
StringRef Module
Definition Wasm.h:389
SmallVector< ValType, 1 > Returns
Definition Wasm.h:516
SmallVector< ValType, 4 > Params
Definition Wasm.h:517
WasmTableType Type
Definition Wasm.h:344