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