1 //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements Wasm object file writer information.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/ADT/SmallPtrSet.h"
16 #include "llvm/BinaryFormat/Wasm.h"
17 #include "llvm/MC/MCAsmBackend.h"
18 #include "llvm/MC/MCAsmLayout.h"
19 #include "llvm/MC/MCAssembler.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCFixupKindInfo.h"
23 #include "llvm/MC/MCObjectWriter.h"
24 #include "llvm/MC/MCSectionWasm.h"
25 #include "llvm/MC/MCSymbolWasm.h"
26 #include "llvm/MC/MCValue.h"
27 #include "llvm/MC/MCWasmObjectWriter.h"
28 #include "llvm/Support/Casting.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/LEB128.h"
32 #include "llvm/Support/StringSaver.h"
37 #define DEBUG_TYPE "mc"
41 // Went we ceate the indirect function table we start at 1, so that there is
42 // and emtpy slot at 0 and therefore calling a null function pointer will trap.
43 static const uint32_t kInitialTableOffset = 1;
45 // For patching purposes, we need to remember where each section starts, both
46 // for patching up the section size field, and for patching up references to
47 // locations within the section.
48 struct SectionBookkeeping {
49 // Where the size of the section is written.
51 // Where the contents of the section starts (after the header).
52 uint64_t ContentsOffset;
56 // The signature of a wasm function, in a struct capable of being used as a
58 struct WasmFunctionType {
59 // Support empty and tombstone instances, needed by DenseMap.
60 enum { Plain, Empty, Tombstone } State;
62 // The return types of the function.
63 SmallVector<wasm::ValType, 1> Returns;
65 // The parameter types of the function.
66 SmallVector<wasm::ValType, 4> Params;
68 WasmFunctionType() : State(Plain) {}
70 bool operator==(const WasmFunctionType &Other) const {
71 return State == Other.State && Returns == Other.Returns &&
72 Params == Other.Params;
76 // Traits for using WasmFunctionType in a DenseMap.
77 struct WasmFunctionTypeDenseMapInfo {
78 static WasmFunctionType getEmptyKey() {
79 WasmFunctionType FuncTy;
80 FuncTy.State = WasmFunctionType::Empty;
83 static WasmFunctionType getTombstoneKey() {
84 WasmFunctionType FuncTy;
85 FuncTy.State = WasmFunctionType::Tombstone;
88 static unsigned getHashValue(const WasmFunctionType &FuncTy) {
89 uintptr_t Value = FuncTy.State;
90 for (wasm::ValType Ret : FuncTy.Returns)
91 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Ret));
92 for (wasm::ValType Param : FuncTy.Params)
93 Value += DenseMapInfo<int32_t>::getHashValue(int32_t(Param));
96 static bool isEqual(const WasmFunctionType &LHS,
97 const WasmFunctionType &RHS) {
102 // A wasm data segment. A wasm binary contains only a single data section
103 // but that can contain many segments, each with their own virtual location
104 // in memory. Each MCSection data created by llvm is modeled as its own
105 // wasm data segment.
106 struct WasmDataSegment {
107 MCSectionWasm *Section;
112 SmallVector<char, 4> Data;
115 // A wasm function to be written into the function section.
116 struct WasmFunction {
118 const MCSymbolWasm *Sym;
121 // A wasm global to be written into the global section.
123 wasm::WasmGlobalType Type;
124 uint64_t InitialValue;
127 // Information about a single item which is part of a COMDAT. For each data
128 // segment or function which is in the COMDAT, there is a corresponding
130 struct WasmComdatEntry {
135 // Information about a single relocation.
136 struct WasmRelocationEntry {
137 uint64_t Offset; // Where is the relocation.
138 const MCSymbolWasm *Symbol; // The symbol to relocate with.
139 int64_t Addend; // A value to add to the symbol.
140 unsigned Type; // The type of the relocation.
141 const MCSectionWasm *FixupSection;// The section the relocation is targeting.
143 WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
144 int64_t Addend, unsigned Type,
145 const MCSectionWasm *FixupSection)
146 : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
147 FixupSection(FixupSection) {}
149 bool hasAddend() const {
151 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
152 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
153 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
160 void print(raw_ostream &Out) const {
161 Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend
163 << ", FixupSection=" << FixupSection->getSectionName();
166 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
167 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
171 struct WasmCustomSection {
173 const SmallVectorImpl<char> &Contents;
175 WasmCustomSection(StringRef Name, const SmallVectorImpl<char> &Contents)
176 : Name(Name), Contents(Contents) {}
180 raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
186 class WasmObjectWriter : public MCObjectWriter {
187 /// The target specific Wasm writer instance.
188 std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
190 // Relocations for fixing up references in the code section.
191 std::vector<WasmRelocationEntry> CodeRelocations;
192 uint32_t CodeSectionIndex;
194 // Relocations for fixing up references in the data section.
195 std::vector<WasmRelocationEntry> DataRelocations;
196 uint32_t DataSectionIndex;
198 // Index values to use for fixing up call_indirect type indices.
199 // Maps function symbols to the index of the type of the function
200 DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
201 // Maps function symbols to the table element index space. Used
202 // for TABLE_INDEX relocation types (i.e. address taken functions).
203 DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
204 // Maps function/global symbols to the (shared) Symbol index space.
205 DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices;
206 // Maps function/global symbols to the function/global Wasm index space.
207 DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
208 // Maps data symbols to the Wasm segment and offset/size with the segment.
209 DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
211 DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo>
213 SmallVector<WasmFunctionType, 4> FunctionTypes;
214 SmallVector<WasmGlobal, 4> Globals;
215 SmallVector<WasmDataSegment, 4> DataSegments;
216 std::vector<WasmCustomSection> CustomSections;
217 unsigned NumFunctionImports = 0;
218 unsigned NumGlobalImports = 0;
219 uint32_t SectionCount = 0;
221 // TargetObjectWriter wrappers.
222 bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
223 unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const {
224 return TargetObjectWriter->getRelocType(Target, Fixup);
227 void startSection(SectionBookkeeping &Section, unsigned SectionId);
228 void startCustomSection(SectionBookkeeping &Section, StringRef Name);
229 void endSection(SectionBookkeeping &Section);
232 WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
233 raw_pwrite_stream &OS)
234 : MCObjectWriter(OS, /*IsLittleEndian=*/true),
235 TargetObjectWriter(std::move(MOTW)) {}
237 ~WasmObjectWriter() override;
240 void reset() override {
241 CodeRelocations.clear();
242 DataRelocations.clear();
244 SymbolIndices.clear();
246 TableIndices.clear();
247 DataLocations.clear();
248 FunctionTypeIndices.clear();
249 FunctionTypes.clear();
251 DataSegments.clear();
252 MCObjectWriter::reset();
253 NumFunctionImports = 0;
254 NumGlobalImports = 0;
257 void writeHeader(const MCAssembler &Asm);
259 void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
260 const MCFragment *Fragment, const MCFixup &Fixup,
261 MCValue Target, uint64_t &FixedValue) override;
263 void executePostLayoutBinding(MCAssembler &Asm,
264 const MCAsmLayout &Layout) override;
266 void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
268 void writeString(const StringRef Str) {
269 encodeULEB128(Str.size(), getStream());
273 void writeValueType(wasm::ValType Ty) {
274 write8(static_cast<uint8_t>(Ty));
277 void writeTypeSection(ArrayRef<WasmFunctionType> FunctionTypes);
278 void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
279 uint32_t NumElements);
280 void writeFunctionSection(ArrayRef<WasmFunction> Functions);
281 void writeGlobalSection();
282 void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
283 void writeElemSection(ArrayRef<uint32_t> TableElems);
284 void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
285 ArrayRef<WasmFunction> Functions);
286 void writeDataSection();
287 void writeRelocSection(uint32_t SectionIndex, StringRef Name,
288 ArrayRef<WasmRelocationEntry> Relocations);
289 void writeLinkingMetaDataSection(
290 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
291 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
292 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
293 void writeUserCustomSections(ArrayRef<WasmCustomSection> CustomSections);
295 uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
296 void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
297 uint64_t ContentsOffset);
299 uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
300 uint32_t getFunctionType(const MCSymbolWasm &Symbol);
301 uint32_t registerFunctionType(const MCSymbolWasm &Symbol);
304 } // end anonymous namespace
306 WasmObjectWriter::~WasmObjectWriter() {}
308 // Write out a section header and a patchable section size field.
309 void WasmObjectWriter::startSection(SectionBookkeeping &Section,
310 unsigned SectionId) {
311 DEBUG(dbgs() << "startSection " << SectionId << "\n");
314 Section.SizeOffset = getStream().tell();
316 // The section size. We don't know the size yet, so reserve enough space
317 // for any 32-bit value; we'll patch it later.
318 encodeULEB128(UINT32_MAX, getStream());
320 // The position where the section starts, for measuring its size.
321 Section.ContentsOffset = getStream().tell();
322 Section.Index = SectionCount++;
325 void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
327 DEBUG(dbgs() << "startCustomSection " << Name << "\n");
328 startSection(Section, wasm::WASM_SEC_CUSTOM);
329 // Custom sections in wasm also have a string identifier.
333 // Now that the section is complete and we know how big it is, patch up the
334 // section size field at the start of the section.
335 void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
336 uint64_t Size = getStream().tell() - Section.ContentsOffset;
337 if (uint32_t(Size) != Size)
338 report_fatal_error("section size does not fit in a uint32_t");
340 DEBUG(dbgs() << "endSection size=" << Size << "\n");
342 // Write the final section size to the payload_len field, which follows
343 // the section id byte.
345 unsigned SizeLen = encodeULEB128(Size, Buffer, 5);
346 assert(SizeLen == 5);
347 getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
350 // Emit the Wasm header.
351 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
352 writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic)));
353 writeLE32(wasm::WasmVersion);
356 void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
357 const MCAsmLayout &Layout) {
360 void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
361 const MCAsmLayout &Layout,
362 const MCFragment *Fragment,
363 const MCFixup &Fixup, MCValue Target,
364 uint64_t &FixedValue) {
365 MCAsmBackend &Backend = Asm.getBackend();
366 bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
367 MCFixupKindInfo::FKF_IsPCRel;
368 const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
369 uint64_t C = Target.getConstant();
370 uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
371 MCContext &Ctx = Asm.getContext();
373 // The .init_array isn't translated as data, so don't do relocations in it.
374 if (FixupSection.getSectionName().startswith(".init_array"))
377 // TODO(sbc): Add support for debug sections.
378 if (FixupSection.getKind().isMetadata())
381 if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
382 assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
383 "Should not have constructed this");
385 // Let A, B and C being the components of Target and R be the location of
386 // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
387 // If it is pcrel, we want to compute (A - B + C - R).
389 // In general, Wasm has no relocations for -B. It can only represent (A + C)
390 // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
391 // replace B to implement it: (A - R - K + C)
395 "No relocation available to represent this relative expression");
399 const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
401 if (SymB.isUndefined()) {
402 Ctx.reportError(Fixup.getLoc(),
403 Twine("symbol '") + SymB.getName() +
404 "' can not be undefined in a subtraction expression");
408 assert(!SymB.isAbsolute() && "Should have been folded");
409 const MCSection &SecB = SymB.getSection();
410 if (&SecB != &FixupSection) {
411 Ctx.reportError(Fixup.getLoc(),
412 "Cannot represent a difference across sections");
416 uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
417 uint64_t K = SymBOffset - FixupOffset;
422 // We either rejected the fixup or folded B into C at this point.
423 const MCSymbolRefExpr *RefA = Target.getSymA();
424 const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
426 if (SymA && SymA->isVariable()) {
427 const MCExpr *Expr = SymA->getVariableValue();
428 const auto *Inner = cast<MCSymbolRefExpr>(Expr);
429 if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
430 llvm_unreachable("weakref used in reloc not yet implemented");
433 // Put any constant offset in an addend. Offsets can be negative, and
434 // LLVM expects wrapping, in contrast to wasm's immediates which can't
435 // be negative and don't wrap.
439 SymA->setUsedInReloc();
444 unsigned Type = getRelocType(Target, Fixup);
446 WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
447 DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
449 // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required
450 // to be against a named symbol.
451 // TODO(sbc): Add support for relocations against unnamed temporaries such
452 // as those generated by llvm's `blockaddress`.
453 // See: test/MC/WebAssembly/blockaddress.ll
454 if (SymA->getName().empty() && Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
455 report_fatal_error("relocations against un-named temporaries are not yet "
456 "supported by wasm");
458 if (FixupSection.isWasmData())
459 DataRelocations.push_back(Rec);
460 else if (FixupSection.getKind().isText())
461 CodeRelocations.push_back(Rec);
463 llvm_unreachable("unexpected section type");
466 // Write X as an (unsigned) LEB value at offset Offset in Stream, padded
467 // to allow patching.
469 WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
471 unsigned SizeLen = encodeULEB128(X, Buffer, 5);
472 assert(SizeLen == 5);
473 Stream.pwrite((char *)Buffer, SizeLen, Offset);
476 // Write X as an signed LEB value at offset Offset in Stream, padded
477 // to allow patching.
479 WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
481 unsigned SizeLen = encodeSLEB128(X, Buffer, 5);
482 assert(SizeLen == 5);
483 Stream.pwrite((char *)Buffer, SizeLen, Offset);
486 // Write X as a plain integer value at offset Offset in Stream.
487 static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
489 support::endian::write32le(Buffer, X);
490 Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
493 static const MCSymbolWasm* ResolveSymbol(const MCSymbolWasm& Symbol) {
494 if (Symbol.isVariable()) {
495 const MCExpr *Expr = Symbol.getVariableValue();
496 auto *Inner = cast<MCSymbolRefExpr>(Expr);
497 return cast<MCSymbolWasm>(&Inner->getSymbol());
502 // Compute a value to write into the code at the location covered
503 // by RelEntry. This value isn't used by the static linker; it just serves
504 // to make the object format more readable and more likely to be directly
507 WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
508 switch (RelEntry.Type) {
509 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
510 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
511 // Provisional value is table address of the resolved symbol itself
512 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol);
513 assert(Sym->isFunction());
514 return TableIndices[Sym];
516 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
517 // Provisional value is same as the index
518 return getRelocationIndexValue(RelEntry);
519 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
520 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
521 // Provisional value is function/global Wasm index
522 if (!WasmIndices.count(RelEntry.Symbol))
523 report_fatal_error("symbol not found in wasm index space: " +
524 RelEntry.Symbol->getName());
525 return WasmIndices[RelEntry.Symbol];
526 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
527 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
528 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: {
529 // Provisional value is address of the global
530 const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol);
531 // For undefined symbols, use zero
532 if (!Sym->isDefined())
534 const wasm::WasmDataReference &Ref = DataLocations[Sym];
535 const WasmDataSegment &Segment = DataSegments[Ref.Segment];
536 // Ignore overflow. LLVM allows address arithmetic to silently wrap.
537 return Segment.Offset + Ref.Offset + RelEntry.Addend;
540 llvm_unreachable("invalid relocation type");
544 static void addData(SmallVectorImpl<char> &DataBytes,
545 MCSectionWasm &DataSection) {
546 DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
548 DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
550 for (const MCFragment &Frag : DataSection) {
551 if (Frag.hasInstructions())
552 report_fatal_error("only data supported in data sections");
554 if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
555 if (Align->getValueSize() != 1)
556 report_fatal_error("only byte values supported for alignment");
557 // If nops are requested, use zeros, as this is the data section.
558 uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
559 uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
560 Align->getAlignment()),
562 Align->getMaxBytesToEmit());
563 DataBytes.resize(Size, Value);
564 } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
566 if (!Fill->getSize().evaluateAsAbsolute(Size))
567 llvm_unreachable("The fill should be an assembler constant");
568 DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
570 const auto &DataFrag = cast<MCDataFragment>(Frag);
571 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
573 DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
577 DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
581 WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
582 if (RelEntry.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) {
583 if (!TypeIndices.count(RelEntry.Symbol))
584 report_fatal_error("symbol not found in type index space: " +
585 RelEntry.Symbol->getName());
586 return TypeIndices[RelEntry.Symbol];
589 if (!SymbolIndices.count(RelEntry.Symbol))
590 report_fatal_error("symbol not found in symbol index space: " +
591 RelEntry.Symbol->getName());
592 return SymbolIndices[RelEntry.Symbol];
595 // Apply the portions of the relocation records that we can handle ourselves
597 void WasmObjectWriter::applyRelocations(
598 ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
599 raw_pwrite_stream &Stream = getStream();
600 for (const WasmRelocationEntry &RelEntry : Relocations) {
601 uint64_t Offset = ContentsOffset +
602 RelEntry.FixupSection->getSectionOffset() +
605 DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
606 uint32_t Value = getProvisionalValue(RelEntry);
608 switch (RelEntry.Type) {
609 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
610 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
611 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
612 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
613 WritePatchableLEB(Stream, Value, Offset);
615 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
616 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
617 WriteI32(Stream, Value, Offset);
619 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
620 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
621 WritePatchableSLEB(Stream, Value, Offset);
624 llvm_unreachable("invalid relocation type");
629 void WasmObjectWriter::writeTypeSection(
630 ArrayRef<WasmFunctionType> FunctionTypes) {
631 if (FunctionTypes.empty())
634 SectionBookkeeping Section;
635 startSection(Section, wasm::WASM_SEC_TYPE);
637 encodeULEB128(FunctionTypes.size(), getStream());
639 for (const WasmFunctionType &FuncTy : FunctionTypes) {
640 write8(wasm::WASM_TYPE_FUNC);
641 encodeULEB128(FuncTy.Params.size(), getStream());
642 for (wasm::ValType Ty : FuncTy.Params)
644 encodeULEB128(FuncTy.Returns.size(), getStream());
645 for (wasm::ValType Ty : FuncTy.Returns)
652 void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
654 uint32_t NumElements) {
658 uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
660 SectionBookkeeping Section;
661 startSection(Section, wasm::WASM_SEC_IMPORT);
663 encodeULEB128(Imports.size(), getStream());
664 for (const wasm::WasmImport &Import : Imports) {
665 writeString(Import.Module);
666 writeString(Import.Field);
669 switch (Import.Kind) {
670 case wasm::WASM_EXTERNAL_FUNCTION:
671 encodeULEB128(Import.SigIndex, getStream());
673 case wasm::WASM_EXTERNAL_GLOBAL:
674 write8(Import.Global.Type);
675 write8(Import.Global.Mutable ? 1 : 0);
677 case wasm::WASM_EXTERNAL_MEMORY:
678 encodeULEB128(0, getStream()); // flags
679 encodeULEB128(NumPages, getStream()); // initial
681 case wasm::WASM_EXTERNAL_TABLE:
682 write8(Import.Table.ElemType);
683 encodeULEB128(0, getStream()); // flags
684 encodeULEB128(NumElements, getStream()); // initial
687 llvm_unreachable("unsupported import kind");
694 void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
695 if (Functions.empty())
698 SectionBookkeeping Section;
699 startSection(Section, wasm::WASM_SEC_FUNCTION);
701 encodeULEB128(Functions.size(), getStream());
702 for (const WasmFunction &Func : Functions)
703 encodeULEB128(Func.Type, getStream());
708 void WasmObjectWriter::writeGlobalSection() {
712 SectionBookkeeping Section;
713 startSection(Section, wasm::WASM_SEC_GLOBAL);
715 encodeULEB128(Globals.size(), getStream());
716 for (const WasmGlobal &Global : Globals) {
717 writeValueType(static_cast<wasm::ValType>(Global.Type.Type));
718 write8(Global.Type.Mutable);
720 write8(wasm::WASM_OPCODE_I32_CONST);
721 encodeSLEB128(Global.InitialValue, getStream());
722 write8(wasm::WASM_OPCODE_END);
728 void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
732 SectionBookkeeping Section;
733 startSection(Section, wasm::WASM_SEC_EXPORT);
735 encodeULEB128(Exports.size(), getStream());
736 for (const wasm::WasmExport &Export : Exports) {
737 writeString(Export.Name);
739 encodeULEB128(Export.Index, getStream());
745 void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
746 if (TableElems.empty())
749 SectionBookkeeping Section;
750 startSection(Section, wasm::WASM_SEC_ELEM);
752 encodeULEB128(1, getStream()); // number of "segments"
753 encodeULEB128(0, getStream()); // the table index
755 // init expr for starting offset
756 write8(wasm::WASM_OPCODE_I32_CONST);
757 encodeSLEB128(kInitialTableOffset, getStream());
758 write8(wasm::WASM_OPCODE_END);
760 encodeULEB128(TableElems.size(), getStream());
761 for (uint32_t Elem : TableElems)
762 encodeULEB128(Elem, getStream());
767 void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
768 const MCAsmLayout &Layout,
769 ArrayRef<WasmFunction> Functions) {
770 if (Functions.empty())
773 SectionBookkeeping Section;
774 startSection(Section, wasm::WASM_SEC_CODE);
775 CodeSectionIndex = Section.Index;
777 encodeULEB128(Functions.size(), getStream());
779 for (const WasmFunction &Func : Functions) {
780 auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection());
783 if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
784 report_fatal_error(".size expression must be evaluatable");
786 encodeULEB128(Size, getStream());
787 FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset);
788 Asm.writeSectionData(&FuncSection, Layout);
792 applyRelocations(CodeRelocations, Section.ContentsOffset);
797 void WasmObjectWriter::writeDataSection() {
798 if (DataSegments.empty())
801 SectionBookkeeping Section;
802 startSection(Section, wasm::WASM_SEC_DATA);
803 DataSectionIndex = Section.Index;
805 encodeULEB128(DataSegments.size(), getStream()); // count
807 for (const WasmDataSegment &Segment : DataSegments) {
808 encodeULEB128(0, getStream()); // memory index
809 write8(wasm::WASM_OPCODE_I32_CONST);
810 encodeSLEB128(Segment.Offset, getStream()); // offset
811 write8(wasm::WASM_OPCODE_END);
812 encodeULEB128(Segment.Data.size(), getStream()); // size
813 Segment.Section->setSectionOffset(getStream().tell() - Section.ContentsOffset);
814 writeBytes(Segment.Data); // data
818 applyRelocations(DataRelocations, Section.ContentsOffset);
823 void WasmObjectWriter::writeRelocSection(
824 uint32_t SectionIndex, StringRef Name,
825 ArrayRef<WasmRelocationEntry> Relocations) {
826 // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
827 // for descriptions of the reloc sections.
829 if (Relocations.empty())
832 SectionBookkeeping Section;
833 startCustomSection(Section, std::string("reloc.") + Name.str());
835 raw_pwrite_stream &Stream = getStream();
837 encodeULEB128(SectionIndex, Stream);
838 encodeULEB128(Relocations.size(), Stream);
839 for (const WasmRelocationEntry& RelEntry : Relocations) {
840 uint64_t Offset = RelEntry.Offset +
841 RelEntry.FixupSection->getSectionOffset();
842 uint32_t Index = getRelocationIndexValue(RelEntry);
844 write8(RelEntry.Type);
845 encodeULEB128(Offset, Stream);
846 encodeULEB128(Index, Stream);
847 if (RelEntry.hasAddend())
848 encodeSLEB128(RelEntry.Addend, Stream);
854 void WasmObjectWriter::writeLinkingMetaDataSection(
855 ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
856 ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
857 const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
858 SectionBookkeeping Section;
859 startCustomSection(Section, "linking");
860 encodeULEB128(wasm::WasmMetadataVersion, getStream());
862 SectionBookkeeping SubSection;
863 if (SymbolInfos.size() != 0) {
864 startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
865 encodeULEB128(SymbolInfos.size(), getStream());
866 for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
867 encodeULEB128(Sym.Kind, getStream());
868 encodeULEB128(Sym.Flags, getStream());
870 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
871 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
872 encodeULEB128(Sym.ElementIndex, getStream());
873 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0)
874 writeString(Sym.Name);
876 case wasm::WASM_SYMBOL_TYPE_DATA:
877 writeString(Sym.Name);
878 if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
879 encodeULEB128(Sym.DataRef.Segment, getStream());
880 encodeULEB128(Sym.DataRef.Offset, getStream());
881 encodeULEB128(Sym.DataRef.Size, getStream());
885 llvm_unreachable("unexpected kind");
888 endSection(SubSection);
891 if (DataSegments.size()) {
892 startSection(SubSection, wasm::WASM_SEGMENT_INFO);
893 encodeULEB128(DataSegments.size(), getStream());
894 for (const WasmDataSegment &Segment : DataSegments) {
895 writeString(Segment.Name);
896 encodeULEB128(Segment.Alignment, getStream());
897 encodeULEB128(Segment.Flags, getStream());
899 endSection(SubSection);
902 if (!InitFuncs.empty()) {
903 startSection(SubSection, wasm::WASM_INIT_FUNCS);
904 encodeULEB128(InitFuncs.size(), getStream());
905 for (auto &StartFunc : InitFuncs) {
906 encodeULEB128(StartFunc.first, getStream()); // priority
907 encodeULEB128(StartFunc.second, getStream()); // function index
909 endSection(SubSection);
912 if (Comdats.size()) {
913 startSection(SubSection, wasm::WASM_COMDAT_INFO);
914 encodeULEB128(Comdats.size(), getStream());
915 for (const auto &C : Comdats) {
916 writeString(C.first);
917 encodeULEB128(0, getStream()); // flags for future use
918 encodeULEB128(C.second.size(), getStream());
919 for (const WasmComdatEntry &Entry : C.second) {
920 encodeULEB128(Entry.Kind, getStream());
921 encodeULEB128(Entry.Index, getStream());
924 endSection(SubSection);
930 void WasmObjectWriter::writeUserCustomSections(
931 ArrayRef<WasmCustomSection> CustomSections) {
932 for (const auto &CustomSection : CustomSections) {
933 SectionBookkeeping Section;
934 startCustomSection(Section, CustomSection.Name);
935 writeBytes(CustomSection.Contents);
940 uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) {
941 assert(Symbol.isFunction());
942 assert(TypeIndices.count(&Symbol));
943 return TypeIndices[&Symbol];
946 uint32_t WasmObjectWriter::registerFunctionType(const MCSymbolWasm& Symbol) {
947 assert(Symbol.isFunction());
950 const MCSymbolWasm* ResolvedSym = ResolveSymbol(Symbol);
951 F.Returns = ResolvedSym->getReturns();
952 F.Params = ResolvedSym->getParams();
955 FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
957 FunctionTypes.push_back(F);
958 TypeIndices[&Symbol] = Pair.first->second;
960 DEBUG(dbgs() << "registerFunctionType: " << Symbol << " new:" << Pair.second << "\n");
961 DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
962 return Pair.first->second;
965 void WasmObjectWriter::writeObject(MCAssembler &Asm,
966 const MCAsmLayout &Layout) {
967 DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
968 MCContext &Ctx = Asm.getContext();
970 // Collect information from the available symbols.
971 SmallVector<WasmFunction, 4> Functions;
972 SmallVector<uint32_t, 4> TableElems;
973 SmallVector<wasm::WasmImport, 4> Imports;
974 SmallVector<wasm::WasmExport, 4> Exports;
975 SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
976 SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
977 std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
978 uint32_t DataSize = 0;
980 // For now, always emit the memory import, since loads and stores are not
981 // valid without it. In the future, we could perhaps be more clever and omit
982 // it if there are no loads or stores.
983 MCSymbolWasm *MemorySym =
984 cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory"));
985 wasm::WasmImport MemImport;
986 MemImport.Module = MemorySym->getModuleName();
987 MemImport.Field = MemorySym->getName();
988 MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
989 Imports.push_back(MemImport);
991 // For now, always emit the table section, since indirect calls are not
992 // valid without it. In the future, we could perhaps be more clever and omit
993 // it if there are no indirect calls.
994 MCSymbolWasm *TableSym =
995 cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table"));
996 wasm::WasmImport TableImport;
997 TableImport.Module = TableSym->getModuleName();
998 TableImport.Field = TableSym->getName();
999 TableImport.Kind = wasm::WASM_EXTERNAL_TABLE;
1000 TableImport.Table.ElemType = wasm::WASM_TYPE_ANYFUNC;
1001 Imports.push_back(TableImport);
1003 // Populate FunctionTypeIndices, and Imports and WasmIndices for undefined
1004 // symbols. This must be done before populating WasmIndices for defined
1006 for (const MCSymbol &S : Asm.symbols()) {
1007 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1009 // Register types for all functions, including those with private linkage
1010 // (because wasm always needs a type signature).
1011 if (WS.isFunction())
1012 registerFunctionType(WS);
1014 if (WS.isTemporary())
1017 // If the symbol is not defined in this translation unit, import it.
1018 if (!WS.isDefined() && !WS.isComdat()) {
1019 if (WS.isFunction()) {
1020 wasm::WasmImport Import;
1021 Import.Module = WS.getModuleName();
1022 Import.Field = WS.getName();
1023 Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
1024 Import.SigIndex = getFunctionType(WS);
1025 Imports.push_back(Import);
1026 WasmIndices[&WS] = NumFunctionImports++;
1027 } else if (WS.isGlobal()) {
1029 report_fatal_error("undefined global symbol cannot be weak");
1031 wasm::WasmImport Import;
1032 Import.Module = WS.getModuleName();
1033 Import.Field = WS.getName();
1034 Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
1035 Import.Global = WS.getGlobalType();
1036 Imports.push_back(Import);
1037 WasmIndices[&WS] = NumGlobalImports++;
1042 // Populate DataSegments, which must be done before populating DataLocations.
1043 for (MCSection &Sec : Asm) {
1044 auto &Section = static_cast<MCSectionWasm &>(Sec);
1046 if (cast<MCSectionWasm>(Sec).getSectionName().startswith(
1047 ".custom_section.")) {
1048 if (Section.getFragmentList().empty())
1050 if (Section.getFragmentList().size() != 1)
1052 "only one .custom_section section fragment supported");
1053 const MCFragment &Frag = *Section.begin();
1054 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1055 report_fatal_error("only data supported in .custom_section section");
1056 const auto &DataFrag = cast<MCDataFragment>(Frag);
1057 if (!DataFrag.getFixups().empty())
1058 report_fatal_error("fixups not supported in .custom_section section");
1059 StringRef UserName = Section.getSectionName().substr(16);
1060 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1061 CustomSections.push_back(WasmCustomSection(UserName, Contents));
1065 if (!Section.isWasmData())
1068 // .init_array sections are handled specially elsewhere.
1069 if (cast<MCSectionWasm>(Sec).getSectionName().startswith(".init_array"))
1072 uint32_t SegmentIndex = DataSegments.size();
1073 DataSize = alignTo(DataSize, Section.getAlignment());
1074 DataSegments.emplace_back();
1075 WasmDataSegment &Segment = DataSegments.back();
1076 Segment.Name = Section.getSectionName();
1077 Segment.Offset = DataSize;
1078 Segment.Section = &Section;
1079 addData(Segment.Data, Section);
1080 Segment.Alignment = Section.getAlignment();
1082 DataSize += Segment.Data.size();
1083 Section.setSegmentIndex(SegmentIndex);
1085 if (const MCSymbolWasm *C = Section.getGroup()) {
1086 Comdats[C->getName()].emplace_back(
1087 WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
1091 // Populate WasmIndices and DataLocations for defined symbols.
1092 for (const MCSymbol &S : Asm.symbols()) {
1093 // Ignore unnamed temporary symbols, which aren't ever exported, imported,
1094 // or used in relocations.
1095 if (S.isTemporary() && S.getName().empty())
1098 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1099 DEBUG(dbgs() << "MCSymbol: '" << S << "'"
1100 << " isDefined=" << S.isDefined()
1101 << " isExternal=" << S.isExternal()
1102 << " isTemporary=" << S.isTemporary()
1103 << " isFunction=" << WS.isFunction()
1104 << " isWeak=" << WS.isWeak()
1105 << " isHidden=" << WS.isHidden()
1106 << " isVariable=" << WS.isVariable() << "\n");
1108 if (WS.isVariable())
1110 if (WS.isComdat() && !WS.isDefined())
1113 if (WS.isFunction()) {
1115 if (WS.isDefined()) {
1116 if (WS.getOffset() != 0)
1118 "function sections must contain one function each");
1120 if (WS.getSize() == 0)
1122 "function symbols must have a size set with .size");
1124 // A definition. Write out the function body.
1125 Index = NumFunctionImports + Functions.size();
1127 Func.Type = getFunctionType(WS);
1129 WasmIndices[&WS] = Index;
1130 Functions.push_back(Func);
1132 auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
1133 if (const MCSymbolWasm *C = Section.getGroup()) {
1134 Comdats[C->getName()].emplace_back(
1135 WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
1138 // An import; the index was assigned above.
1139 Index = WasmIndices.find(&WS)->second;
1142 DEBUG(dbgs() << " -> function index: " << Index << "\n");
1143 } else if (WS.isData()) {
1144 if (WS.isTemporary() && !WS.getSize())
1147 if (!WS.isDefined()) {
1148 DEBUG(dbgs() << " -> segment index: -1");
1153 report_fatal_error("data symbols must have a size set with .size: " +
1157 if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
1158 report_fatal_error(".size expression must be evaluatable");
1160 auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
1161 assert(DataSection.isWasmData());
1163 // For each data symbol, export it in the symtab as a reference to the
1164 // corresponding Wasm data segment.
1165 wasm::WasmDataReference Ref = wasm::WasmDataReference{
1166 DataSection.getSegmentIndex(),
1167 static_cast<uint32_t>(Layout.getSymbolOffset(WS)),
1168 static_cast<uint32_t>(Size)};
1169 DataLocations[&WS] = Ref;
1170 DEBUG(dbgs() << " -> segment index: " << Ref.Segment);
1172 // A "true" Wasm global (currently just __stack_pointer)
1174 report_fatal_error("don't yet support defined globals");
1176 // An import; the index was assigned above
1177 DEBUG(dbgs() << " -> global index: " << WasmIndices.find(&WS)->second
1182 // Populate WasmIndices and DataLocations for aliased symbols. We need to
1183 // process these in a separate pass because we need to have processed the
1184 // target of the alias before the alias itself and the symbols are not
1185 // necessarily ordered in this way.
1186 for (const MCSymbol &S : Asm.symbols()) {
1187 if (!S.isVariable())
1190 assert(S.isDefined());
1192 // Find the target symbol of this weak alias and export that index
1193 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1194 const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS);
1195 DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n");
1197 if (WS.isFunction()) {
1198 assert(WasmIndices.count(ResolvedSym) > 0);
1199 uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
1200 WasmIndices[&WS] = WasmIndex;
1201 DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
1202 } else if (WS.isData()) {
1203 assert(DataLocations.count(ResolvedSym) > 0);
1204 const wasm::WasmDataReference &Ref =
1205 DataLocations.find(ResolvedSym)->second;
1206 DataLocations[&WS] = Ref;
1207 DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
1209 report_fatal_error("don't yet support global aliases");
1213 // Finally, populate the symbol table itself, in its "natural" order.
1214 for (const MCSymbol &S : Asm.symbols()) {
1215 const auto &WS = static_cast<const MCSymbolWasm &>(S);
1216 if (WS.isTemporary() && WS.getName().empty())
1218 if (WS.isComdat() && !WS.isDefined())
1220 if (WS.isTemporary() && WS.isData() && !WS.getSize())
1225 Flags |= wasm::WASM_SYMBOL_BINDING_WEAK;
1227 Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
1228 if (!WS.isExternal() && WS.isDefined())
1229 Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
1230 if (WS.isUndefined())
1231 Flags |= wasm::WASM_SYMBOL_UNDEFINED;
1233 wasm::WasmSymbolInfo Info;
1234 Info.Name = WS.getName();
1235 Info.Kind = WS.getType();
1238 Info.ElementIndex = WasmIndices.find(&WS)->second;
1239 else if (WS.isDefined())
1240 Info.DataRef = DataLocations.find(&WS)->second;
1241 SymbolIndices[&WS] = SymbolInfos.size();
1242 SymbolInfos.emplace_back(Info);
1246 auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
1247 // Functions referenced by a relocation need to put in the table. This is
1248 // purely to make the object file's provisional values readable, and is
1249 // ignored by the linker, which re-calculates the relocations itself.
1250 if (Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 &&
1251 Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB)
1253 assert(Rel.Symbol->isFunction());
1254 const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol);
1255 uint32_t FunctionIndex = WasmIndices.find(&WS)->second;
1256 uint32_t TableIndex = TableElems.size() + kInitialTableOffset;
1257 if (TableIndices.try_emplace(&WS, TableIndex).second) {
1258 DEBUG(dbgs() << " -> adding " << WS.getName()
1259 << " to table: " << TableIndex << "\n");
1260 TableElems.push_back(FunctionIndex);
1261 registerFunctionType(WS);
1265 for (const WasmRelocationEntry &RelEntry : CodeRelocations)
1266 HandleReloc(RelEntry);
1267 for (const WasmRelocationEntry &RelEntry : DataRelocations)
1268 HandleReloc(RelEntry);
1271 // Translate .init_array section contents into start functions.
1272 for (const MCSection &S : Asm) {
1273 const auto &WS = static_cast<const MCSectionWasm &>(S);
1274 if (WS.getSectionName().startswith(".fini_array"))
1275 report_fatal_error(".fini_array sections are unsupported");
1276 if (!WS.getSectionName().startswith(".init_array"))
1278 if (WS.getFragmentList().empty())
1280 if (WS.getFragmentList().size() != 2)
1281 report_fatal_error("only one .init_array section fragment supported");
1282 const MCFragment &AlignFrag = *WS.begin();
1283 if (AlignFrag.getKind() != MCFragment::FT_Align)
1284 report_fatal_error(".init_array section should be aligned");
1285 if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4))
1286 report_fatal_error(".init_array section should be aligned for pointers");
1287 const MCFragment &Frag = *std::next(WS.begin());
1288 if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
1289 report_fatal_error("only data supported in .init_array section");
1290 uint16_t Priority = UINT16_MAX;
1291 if (WS.getSectionName().size() != 11) {
1292 if (WS.getSectionName()[11] != '.')
1293 report_fatal_error(".init_array section priority should start with '.'");
1294 if (WS.getSectionName().substr(12).getAsInteger(10, Priority))
1295 report_fatal_error("invalid .init_array section priority");
1297 const auto &DataFrag = cast<MCDataFragment>(Frag);
1298 const SmallVectorImpl<char> &Contents = DataFrag.getContents();
1299 for (const uint8_t *p = (const uint8_t *)Contents.data(),
1300 *end = (const uint8_t *)Contents.data() + Contents.size();
1303 report_fatal_error("non-symbolic data in .init_array section");
1305 for (const MCFixup &Fixup : DataFrag.getFixups()) {
1306 assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
1307 const MCExpr *Expr = Fixup.getValue();
1308 auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr);
1310 report_fatal_error("fixups in .init_array should be symbol references");
1311 if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION)
1312 report_fatal_error("symbols in .init_array should be for functions");
1313 auto I = SymbolIndices.find(cast<MCSymbolWasm>(&Sym->getSymbol()));
1314 if (I == SymbolIndices.end())
1315 report_fatal_error("symbols in .init_array should be defined");
1316 uint32_t Index = I->second;
1317 InitFuncs.push_back(std::make_pair(Priority, Index));
1321 // Write out the Wasm header.
1324 writeTypeSection(FunctionTypes);
1325 writeImportSection(Imports, DataSize, TableElems.size());
1326 writeFunctionSection(Functions);
1327 // Skip the "table" section; we import the table instead.
1328 // Skip the "memory" section; we import the memory instead.
1329 writeGlobalSection();
1330 writeExportSection(Exports);
1331 writeElemSection(TableElems);
1332 writeCodeSection(Asm, Layout, Functions);
1334 writeUserCustomSections(CustomSections);
1335 writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
1336 writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
1337 writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
1339 // TODO: Translate the .comment section to the output.
1340 // TODO: Translate debug sections to the output.
1343 std::unique_ptr<MCObjectWriter>
1344 llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
1345 raw_pwrite_stream &OS) {
1346 return llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS);