brintos

brintos / llvm-project-archived public Read only

0
0
Text · 74.4 KiB · 91d8f6b Raw
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