diff options
Diffstat (limited to 'lib/MC/WasmObjectWriter.cpp')
-rw-r--r-- | lib/MC/WasmObjectWriter.cpp | 423 |
1 files changed, 229 insertions, 194 deletions
diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 0cca3757be90..098343cd0107 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -1,9 +1,8 @@ //===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -41,7 +40,7 @@ namespace { // Went we ceate the indirect function table we start at 1, so that there is // and emtpy slot at 0 and therefore calling a null function pointer will trap. -static const uint32_t kInitialTableOffset = 1; +static const uint32_t InitialTableOffset = 1; // For patching purposes, we need to remember where each section starts, both // for patching up the section size field, and for patching up references to @@ -61,7 +60,7 @@ struct SectionBookkeeping { // TODO: Consider using wasm::WasmSignature directly instead. struct WasmSignature { // Support empty and tombstone instances, needed by DenseMap. - enum { Plain, Empty, Tombstone } State; + enum { Plain, Empty, Tombstone } State = Plain; // The return types of the function. SmallVector<wasm::ValType, 1> Returns; @@ -69,8 +68,6 @@ struct WasmSignature { // The parameter types of the function. SmallVector<wasm::ValType, 4> Params; - WasmSignature() : State(Plain) {} - bool operator==(const WasmSignature &Other) const { return State == Other.State && Returns == Other.Returns && Params == Other.Params; @@ -109,9 +106,10 @@ struct WasmSignatureDenseMapInfo { struct WasmDataSegment { MCSectionWasm *Section; StringRef Name; + uint32_t InitFlags; uint32_t Offset; uint32_t Alignment; - uint32_t Flags; + uint32_t LinkerFlags; SmallVector<char, 4> Data; }; @@ -149,18 +147,7 @@ struct WasmRelocationEntry { : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), FixupSection(FixupSection) {} - bool hasAddend() const { - switch (Type) { - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: - case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: - return true; - default: - return false; - } - } + bool hasAddend() const { return wasm::relocTypeHasAddend(Type); } void print(raw_ostream &Out) const { Out << wasm::relocTypetoString(Type) << " Off=" << Offset @@ -173,7 +160,7 @@ struct WasmRelocationEntry { #endif }; -static const uint32_t INVALID_INDEX = -1; +static const uint32_t InvalidIndex = -1; struct WasmCustomSection { @@ -185,7 +172,7 @@ struct WasmCustomSection { WasmCustomSection(StringRef Name, MCSectionWasm *Section) : Name(Name), Section(Section), OutputContentsOffset(0), - OutputIndex(INVALID_INDEX) {} + OutputIndex(InvalidIndex) {} }; #if !defined(NDEBUG) @@ -195,6 +182,33 @@ raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { } #endif +// Write X as an (unsigned) LEB value at offset Offset in Stream, padded +// to allow patching. +static void writePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, + uint64_t Offset) { + uint8_t Buffer[5]; + unsigned SizeLen = encodeULEB128(X, Buffer, 5); + assert(SizeLen == 5); + Stream.pwrite((char *)Buffer, SizeLen, Offset); +} + +// Write X as an signed LEB value at offset Offset in Stream, padded +// to allow patching. +static void writePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, + uint64_t Offset) { + uint8_t Buffer[5]; + unsigned SizeLen = encodeSLEB128(X, Buffer, 5); + assert(SizeLen == 5); + Stream.pwrite((char *)Buffer, SizeLen, Offset); +} + +// Write X as a plain integer value at offset Offset in Stream. +static void writeI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { + uint8_t Buffer[4]; + support::endian::write32le(Buffer, X); + Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); +} + class WasmObjectWriter : public MCObjectWriter { support::endian::Writer W; @@ -218,12 +232,15 @@ class WasmObjectWriter : public MCObjectWriter { // Maps function/global symbols to the function/global/event/section index // space. DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; + DenseMap<const MCSymbolWasm *, uint32_t> GOTIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; // Stores output data (index, relocations, content offset) for custom // section. std::vector<WasmCustomSection> CustomSections; + std::unique_ptr<WasmCustomSection> ProducersSection; + std::unique_ptr<WasmCustomSection> TargetFeaturesSection; // Relocations for fixing up references in the custom sections. DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>> CustomSectionsRelocations; @@ -233,7 +250,6 @@ class WasmObjectWriter : public MCObjectWriter { DenseMap<WasmSignature, uint32_t, WasmSignatureDenseMapInfo> SignatureIndices; SmallVector<WasmSignature, 4> Signatures; - SmallVector<WasmGlobal, 4> Globals; SmallVector<WasmDataSegment, 4> DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; @@ -242,9 +258,6 @@ class WasmObjectWriter : public MCObjectWriter { // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } - unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const { - return TargetObjectWriter->getRelocType(Target, Fixup); - } void startSection(SectionBookkeeping &Section, unsigned SectionId); void startCustomSection(SectionBookkeeping &Section, StringRef Name); @@ -255,20 +268,21 @@ public: raw_pwrite_stream &OS) : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {} - ~WasmObjectWriter() override; - private: void reset() override { CodeRelocations.clear(); DataRelocations.clear(); TypeIndices.clear(); WasmIndices.clear(); + GOTIndices.clear(); TableIndices.clear(); DataLocations.clear(); + CustomSections.clear(); + ProducersSection.reset(); + TargetFeaturesSection.reset(); CustomSectionsRelocations.clear(); SignatureIndices.clear(); Signatures.clear(); - Globals.clear(); DataSegments.clear(); SectionFunctions.clear(); NumFunctionImports = 0; @@ -298,9 +312,9 @@ private: void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, uint32_t NumElements); void writeFunctionSection(ArrayRef<WasmFunction> Functions); - void writeGlobalSection(); void writeExportSection(ArrayRef<wasm::WasmExport> Exports); void writeElemSection(ArrayRef<uint32_t> TableElems); + void writeDataCountSection(); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef<WasmFunction> Functions); void writeDataSection(); @@ -311,7 +325,8 @@ private: ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats); - void writeCustomSections(const MCAssembler &Asm, const MCAsmLayout &Layout); + void writeCustomSection(WasmCustomSection &CustomSection, + const MCAssembler &Asm, const MCAsmLayout &Layout); void writeCustomRelocSections(); void updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions, @@ -330,8 +345,6 @@ private: } // end anonymous namespace -WasmObjectWriter::~WasmObjectWriter() {} - // Write out a section header and a patchable section size field. void WasmObjectWriter::startSection(SectionBookkeeping &Section, unsigned SectionId) { @@ -342,7 +355,7 @@ void WasmObjectWriter::startSection(SectionBookkeeping &Section, // The section size. We don't know the size yet, so reserve enough space // for any 32-bit value; we'll patch it later. - encodeULEB128(UINT32_MAX, W.OS); + encodeULEB128(0, W.OS, 5); // The position where the section starts, for measuring its size. Section.ContentsOffset = W.OS.tell(); @@ -368,7 +381,13 @@ void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section, // Now that the section is complete and we know how big it is, patch up the // section size field at the start of the section. void WasmObjectWriter::endSection(SectionBookkeeping &Section) { - uint64_t Size = W.OS.tell() - Section.PayloadOffset; + uint64_t Size = W.OS.tell(); + // /dev/null doesn't support seek/tell and can report offset of 0. + // Simply skip this patching in that case. + if (!Size) + return; + + Size -= Section.PayloadOffset; if (uint32_t(Size) != Size) report_fatal_error("section size does not fit in a uint32_t"); @@ -376,11 +395,8 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) { // Write the final section size to the payload_len field, which follows // the section id byte. - uint8_t Buffer[16]; - unsigned SizeLen = encodeULEB128(Size, Buffer, 5); - assert(SizeLen == 5); - static_cast<raw_pwrite_stream &>(W.OS).pwrite((char *)Buffer, SizeLen, - Section.SizeOffset); + writePatchableLEB(static_cast<raw_pwrite_stream &>(W.OS), Size, + Section.SizeOffset); } // Emit the Wasm header. @@ -479,15 +495,15 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, // be negative and don't wrap. FixedValue = 0; - unsigned Type = getRelocType(Target, Fixup); + unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup); assert(!IsPCRel); assert(SymA); // Absolute offset within a section or a function. // Currently only supported for for metadata sections. // See: test/MC/WebAssembly/blockaddress.ll - if (Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32 || - Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32) { + if (Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || + Type == wasm::R_WASM_SECTION_OFFSET_I32) { if (!FixupSection.getKind().isMetadata()) report_fatal_error("relocations for function or section offsets are " "only supported in metadata sections"); @@ -505,9 +521,9 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, SymA = cast<MCSymbolWasm>(SectionSymbol); } - // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are required to be + // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be // against a named symbol. - if (Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) { + if (Type != wasm::R_WASM_TYPE_INDEX_LEB) { if (SymA->getName().empty()) report_fatal_error("relocations against un-named temporaries are not yet " "supported by wasm"); @@ -515,6 +531,9 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, SymA->setUsedInReloc(); } + if (RefA->getKind() == MCSymbolRefExpr::VK_GOT) + SymA->setUsedInGOT(); + WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); @@ -529,40 +548,14 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, } } -// Write X as an (unsigned) LEB value at offset Offset in Stream, padded -// to allow patching. -static void WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, - uint64_t Offset) { - uint8_t Buffer[5]; - unsigned SizeLen = encodeULEB128(X, Buffer, 5); - assert(SizeLen == 5); - Stream.pwrite((char *)Buffer, SizeLen, Offset); -} - -// Write X as an signed LEB value at offset Offset in Stream, padded -// to allow patching. -static void WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, - uint64_t Offset) { - uint8_t Buffer[5]; - unsigned SizeLen = encodeSLEB128(X, Buffer, 5); - assert(SizeLen == 5); - Stream.pwrite((char *)Buffer, SizeLen, Offset); -} - -// Write X as a plain integer value at offset Offset in Stream. -static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) { - uint8_t Buffer[4]; - support::endian::write32le(Buffer, X); - Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); -} - -static const MCSymbolWasm *ResolveSymbol(const MCSymbolWasm &Symbol) { - if (Symbol.isVariable()) { - const MCExpr *Expr = Symbol.getVariableValue(); +static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) { + const MCSymbolWasm* Ret = &Symbol; + while (Ret->isVariable()) { + const MCExpr *Expr = Ret->getVariableValue(); auto *Inner = cast<MCSymbolRefExpr>(Expr); - return cast<MCSymbolWasm>(&Inner->getSymbol()); + Ret = cast<MCSymbolWasm>(&Inner->getSymbol()); } - return &Symbol; + return Ret; } // Compute a value to write into the code at the location covered @@ -571,36 +564,41 @@ static const MCSymbolWasm *ResolveSymbol(const MCSymbolWasm &Symbol) { // useable. uint32_t WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { + if (RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB && !RelEntry.Symbol->isGlobal()) { + assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space"); + return GOTIndices[RelEntry.Symbol]; + } + switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: { + case wasm::R_WASM_TABLE_INDEX_REL_SLEB: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_I32: { // Provisional value is table address of the resolved symbol itself - const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); + const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); assert(Sym->isFunction()); return TableIndices[Sym]; } - case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + case wasm::R_WASM_TYPE_INDEX_LEB: // Provisional value is same as the index return getRelocationIndexValue(RelEntry); - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_EVENT_INDEX_LEB: // Provisional value is function/global/event Wasm index - if (!WasmIndices.count(RelEntry.Symbol)) - report_fatal_error("symbol not found in wasm index space: " + - RelEntry.Symbol->getName()); + assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space"); return WasmIndices[RelEntry.Symbol]; - case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: - case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: { const auto &Section = static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection()); return Section.getSectionOffset() + RelEntry.Addend; } - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: { // Provisional value is address of the global - const MCSymbolWasm *Sym = ResolveSymbol(*RelEntry.Symbol); + const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); // For undefined symbols, use zero if (!Sym->isDefined()) return 0; @@ -654,7 +652,7 @@ static void addData(SmallVectorImpl<char> &DataBytes, uint32_t WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) { - if (RelEntry.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) { + if (RelEntry.Type == wasm::R_WASM_TYPE_INDEX_LEB) { if (!TypeIndices.count(RelEntry.Symbol)) report_fatal_error("symbol not found in type index space: " + RelEntry.Symbol->getName()); @@ -678,22 +676,24 @@ void WasmObjectWriter::applyRelocations( uint32_t Value = getProvisionalValue(RelEntry); switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: - WritePatchableLEB(Stream, Value, Offset); + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_TYPE_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_EVENT_INDEX_LEB: + writePatchableLEB(Stream, Value, Offset); break; - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: - case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: - WriteI32(Stream, Value, Offset); + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: + writeI32(Stream, Value, Offset); break; - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - WritePatchableSLEB(Stream, Value, Offset); + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_REL_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: + writePatchableSLEB(Stream, Value, Offset); break; default: llvm_unreachable("invalid relocation type"); @@ -783,26 +783,6 @@ void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) { endSection(Section); } -void WasmObjectWriter::writeGlobalSection() { - if (Globals.empty()) - return; - - SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_GLOBAL); - - encodeULEB128(Globals.size(), W.OS); - for (const WasmGlobal &Global : Globals) { - writeValueType(static_cast<wasm::ValType>(Global.Type.Type)); - W.OS << char(Global.Type.Mutable); - - W.OS << char(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(Global.InitialValue, W.OS); - W.OS << char(wasm::WASM_OPCODE_END); - } - - endSection(Section); -} - void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) { if (Events.empty()) return; @@ -848,7 +828,7 @@ void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { // init expr for starting offset W.OS << char(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(kInitialTableOffset, W.OS); + encodeSLEB128(InitialTableOffset, W.OS); W.OS << char(wasm::WASM_OPCODE_END); encodeULEB128(TableElems.size(), W.OS); @@ -858,6 +838,16 @@ void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) { endSection(Section); } +void WasmObjectWriter::writeDataCountSection() { + if (DataSegments.empty()) + return; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_DATACOUNT); + encodeULEB128(DataSegments.size(), W.OS); + endSection(Section); +} + void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef<WasmFunction> Functions) { @@ -899,10 +889,14 @@ void WasmObjectWriter::writeDataSection() { encodeULEB128(DataSegments.size(), W.OS); // count for (const WasmDataSegment &Segment : DataSegments) { - encodeULEB128(0, W.OS); // memory index - W.OS << char(wasm::WASM_OPCODE_I32_CONST); - encodeSLEB128(Segment.Offset, W.OS); // offset - W.OS << char(wasm::WASM_OPCODE_END); + encodeULEB128(Segment.InitFlags, W.OS); // flags + if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX) + encodeULEB128(0, W.OS); // memory index + if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) { + W.OS << char(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Segment.Offset, W.OS); // offset + W.OS << char(wasm::WASM_OPCODE_END); + } encodeULEB128(Segment.Data.size(), W.OS); // size Segment.Section->setSectionOffset(W.OS.tell() - Section.ContentsOffset); W.OS << Segment.Data; // data @@ -928,9 +922,8 @@ void WasmObjectWriter::writeRelocSection( // order, but for the code section we combine many MC sections into single // wasm section, and this order is determined by the order of Asm.Symbols() // not the sections order. - std::stable_sort( - Relocs.begin(), Relocs.end(), - [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) { + llvm::stable_sort( + Relocs, [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) { return (A.Offset + A.FixupSection->getSectionOffset()) < (B.Offset + B.FixupSection->getSectionOffset()); }); @@ -982,7 +975,8 @@ void WasmObjectWriter::writeLinkingMetaDataSection( case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_EVENT: encodeULEB128(Sym.ElementIndex, W.OS); - if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) + if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 || + (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) writeString(Sym.Name); break; case wasm::WASM_SYMBOL_TYPE_DATA: @@ -1012,7 +1006,7 @@ void WasmObjectWriter::writeLinkingMetaDataSection( for (const WasmDataSegment &Segment : DataSegments) { writeString(Segment.Name); encodeULEB128(Segment.Alignment, W.OS); - encodeULEB128(Segment.Flags, W.OS); + encodeULEB128(Segment.LinkerFlags, W.OS); } endSection(SubSection); } @@ -1045,25 +1039,24 @@ void WasmObjectWriter::writeLinkingMetaDataSection( endSection(Section); } -void WasmObjectWriter::writeCustomSections(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - for (auto &CustomSection : CustomSections) { - SectionBookkeeping Section; - auto *Sec = CustomSection.Section; - startCustomSection(Section, CustomSection.Name); +void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection, + const MCAssembler &Asm, + const MCAsmLayout &Layout) { + SectionBookkeeping Section; + auto *Sec = CustomSection.Section; + startCustomSection(Section, CustomSection.Name); - Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset); - Asm.writeSectionData(W.OS, Sec, Layout); + Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset); + Asm.writeSectionData(W.OS, Sec, Layout); - CustomSection.OutputContentsOffset = Section.ContentsOffset; - CustomSection.OutputIndex = Section.Index; + CustomSection.OutputContentsOffset = Section.ContentsOffset; + CustomSection.OutputIndex = Section.Index; - endSection(Section); + endSection(Section); - // Apply fixups. - auto &Relocations = CustomSectionsRelocations[CustomSection.Section]; - applyRelocations(Relocations, CustomSection.OutputContentsOffset); - } + // Apply fixups. + auto &Relocations = CustomSectionsRelocations[CustomSection.Section]; + applyRelocations(Relocations, CustomSection.OutputContentsOffset); } uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) { @@ -1082,7 +1075,7 @@ void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { assert(Symbol.isFunction()); WasmSignature S; - const MCSymbolWasm *ResolvedSym = ResolveSymbol(Symbol); + const MCSymbolWasm *ResolvedSym = resolveSymbol(Symbol); if (auto *Sig = ResolvedSym->getSignature()) { S.Returns = Sig->Returns; S.Params = Sig->Params; @@ -1143,7 +1136,6 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, uint64_t StartOffset = W.OS.tell(); LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); - MCContext &Ctx = Asm.getContext(); // Collect information from the available symbols. SmallVector<WasmFunction, 4> Functions; @@ -1159,22 +1151,18 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // For now, always emit the memory import, since loads and stores are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no loads or stores. - MCSymbolWasm *MemorySym = - cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory")); wasm::WasmImport MemImport; - MemImport.Module = MemorySym->getModuleName(); - MemImport.Field = MemorySym->getName(); + MemImport.Module = "env"; + MemImport.Field = "__linear_memory"; MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; Imports.push_back(MemImport); // For now, always emit the table section, since indirect calls are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no indirect calls. - MCSymbolWasm *TableSym = - cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table")); wasm::WasmImport TableImport; - TableImport.Module = TableSym->getModuleName(); - TableImport.Field = TableSym->getName(); + TableImport.Module = "env"; + TableImport.Field = "__indirect_function_table"; TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF; Imports.push_back(TableImport); @@ -1200,39 +1188,60 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.isDefined() && !WS.isComdat()) { if (WS.isFunction()) { wasm::WasmImport Import; - Import.Module = WS.getModuleName(); - Import.Field = WS.getName(); + Import.Module = WS.getImportModule(); + Import.Field = WS.getImportName(); Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; Import.SigIndex = getFunctionType(WS); Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumFunctionImports++; } else if (WS.isGlobal()) { if (WS.isWeak()) report_fatal_error("undefined global symbol cannot be weak"); wasm::WasmImport Import; - Import.Module = WS.getModuleName(); - Import.Field = WS.getName(); + Import.Field = WS.getImportName(); Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; + Import.Module = WS.getImportModule(); Import.Global = WS.getGlobalType(); Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumGlobalImports++; } else if (WS.isEvent()) { if (WS.isWeak()) report_fatal_error("undefined event symbol cannot be weak"); wasm::WasmImport Import; - Import.Module = WS.getModuleName(); - Import.Field = WS.getName(); + Import.Module = WS.getImportModule(); + Import.Field = WS.getImportName(); Import.Kind = wasm::WASM_EXTERNAL_EVENT; Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; Import.Event.SigIndex = getEventType(WS); Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumEventImports++; } } } + // Add imports for GOT globals + for (const MCSymbol &S : Asm.symbols()) { + const auto &WS = static_cast<const MCSymbolWasm &>(S); + if (WS.isUsedInGOT()) { + wasm::WasmImport Import; + if (WS.isFunction()) + Import.Module = "GOT.func"; + else + Import.Module = "GOT.mem"; + Import.Field = WS.getName(); + Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; + Import.Global = {wasm::WASM_TYPE_I32, true}; + Imports.push_back(Import); + assert(GOTIndices.count(&WS) == 0); + GOTIndices[&WS] = NumGlobalImports++; + } + } + // Populate DataSegments and CustomSections, which must be done before // populating DataLocations. for (MCSection &Sec : Asm) { @@ -1253,11 +1262,13 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, DataSegments.emplace_back(); WasmDataSegment &Segment = DataSegments.back(); Segment.Name = SectionName; + Segment.InitFlags = + Section.getPassive() ? (uint32_t)wasm::WASM_SEGMENT_IS_PASSIVE : 0; Segment.Offset = DataSize; Segment.Section = &Section; addData(Segment.Data, Section); Segment.Alignment = Log2_32(Section.getAlignment()); - Segment.Flags = 0; + Segment.LinkerFlags = 0; DataSize += Segment.Data.size(); Section.setSegmentIndex(SegmentIndex); @@ -1282,6 +1293,18 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error("section name and begin symbol should match: " + Twine(SectionName)); } + + // Separate out the producers and target features sections + if (Name == "producers") { + ProducersSection = llvm::make_unique<WasmCustomSection>(Name, &Section); + continue; + } + if (Name == "target_features") { + TargetFeaturesSection = + llvm::make_unique<WasmCustomSection>(Name, &Section); + continue; + } + CustomSections.emplace_back(Name, &Section); } } @@ -1313,7 +1336,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error( "function sections must contain one function each"); - if (WS.getSize() == 0) + if (WS.getSize() == nullptr) report_fatal_error( "function symbols must have a size set with .size"); @@ -1338,7 +1361,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n"); } else if (WS.isData()) { - if (WS.isTemporary() && !WS.getSize()) + if (!isInSymtab(WS)) continue; if (!WS.isDefined()) { @@ -1384,11 +1407,12 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, wasm::WasmEventType Event; Event.SigIndex = getEventType(WS); Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION; + assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = Index; Events.push_back(Event); } else { // An import; the index was assigned above. - Index = WasmIndices.find(&WS)->second; + assert(WasmIndices.count(&WS) > 0); } LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second << "\n"); @@ -1410,16 +1434,17 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Find the target symbol of this weak alias and export that index const auto &WS = static_cast<const MCSymbolWasm &>(S); - const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); + const MCSymbolWasm *ResolvedSym = resolveSymbol(WS); LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); - if (WS.isFunction()) { + if (ResolvedSym->isFunction()) { assert(WasmIndices.count(ResolvedSym) > 0); uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; + assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = WasmIndex; LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); - } else if (WS.isData()) { + } else if (ResolvedSym->isData()) { assert(DataLocations.count(ResolvedSym) > 0); const wasm::WasmDataReference &Ref = DataLocations.find(ResolvedSym)->second; @@ -1434,7 +1459,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, for (const MCSymbol &S : Asm.symbols()) { const auto &WS = static_cast<const MCSymbolWasm &>(S); if (!isInSymtab(WS)) { - WS.setIndex(INVALID_INDEX); + WS.setIndex(InvalidIndex); continue; } LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n"); @@ -1448,6 +1473,10 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; if (WS.isUndefined()) Flags |= wasm::WASM_SYMBOL_UNDEFINED; + if (WS.isExported()) + Flags |= wasm::WASM_SYMBOL_EXPORTED; + if (WS.getName() != WS.getImportName()) + Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME; wasm::WasmSymbolInfo Info; Info.Name = WS.getName(); @@ -1469,13 +1498,13 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Functions referenced by a relocation need to put in the table. This is // purely to make the object file's provisional values readable, and is // ignored by the linker, which re-calculates the relocations itself. - if (Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 && - Rel.Type != wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB) + if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 && + Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB) return; assert(Rel.Symbol->isFunction()); - const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol); + const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol); uint32_t FunctionIndex = WasmIndices.find(&WS)->second; - uint32_t TableIndex = TableElems.size() + kInitialTableOffset; + uint32_t TableIndex = TableElems.size() + InitialTableOffset; if (TableIndices.try_emplace(&WS, TableIndex).second) { LLVM_DEBUG(dbgs() << " -> adding " << WS.getName() << " to table: " << TableIndex << "\n"); @@ -1534,25 +1563,26 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, const auto &DataFrag = cast<MCDataFragment>(Frag); const SmallVectorImpl<char> &Contents = DataFrag.getContents(); for (const uint8_t * - p = (const uint8_t *)Contents.data(), - *end = (const uint8_t *)Contents.data() + Contents.size(); - p != end; ++p) { - if (*p != 0) + P = (const uint8_t *)Contents.data(), + *End = (const uint8_t *)Contents.data() + Contents.size(); + P != End; ++P) { + if (*P != 0) report_fatal_error("non-symbolic data in .init_array section"); } for (const MCFixup &Fixup : DataFrag.getFixups()) { assert(Fixup.getKind() == MCFixup::getKindForSize(is64Bit() ? 8 : 4, false)); const MCExpr *Expr = Fixup.getValue(); - auto *Sym = dyn_cast<MCSymbolRefExpr>(Expr); - if (!Sym) + auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr); + if (!SymRef) report_fatal_error("fixups in .init_array should be symbol references"); - if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION) - report_fatal_error("symbols in .init_array should be for functions"); - if (Sym->getSymbol().getIndex() == INVALID_INDEX) + const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol()); + if (TargetSym.getIndex() == InvalidIndex) report_fatal_error("symbols in .init_array should exist in symbtab"); + if (!TargetSym.isFunction()) + report_fatal_error("symbols in .init_array should be for functions"); InitFuncs.push_back( - std::make_pair(Priority, Sym->getSymbol().getIndex())); + std::make_pair(Priority, TargetSym.getIndex())); } } @@ -1564,17 +1594,22 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, writeFunctionSection(Functions); // Skip the "table" section; we import the table instead. // Skip the "memory" section; we import the memory instead. - writeGlobalSection(); writeEventSection(Events); writeExportSection(Exports); writeElemSection(TableElems); + writeDataCountSection(); writeCodeSection(Asm, Layout, Functions); writeDataSection(); - writeCustomSections(Asm, Layout); + for (auto &CustomSection : CustomSections) + writeCustomSection(CustomSection, Asm, Layout); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations); writeRelocSection(DataSectionIndex, "DATA", DataRelocations); writeCustomRelocSections(); + if (ProducersSection) + writeCustomSection(*ProducersSection, Asm, Layout); + if (TargetFeaturesSection) + writeCustomSection(*TargetFeaturesSection, Asm, Layout); // TODO: Translate the .comment section to the output. return W.OS.tell() - StartOffset; |