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