diff options
Diffstat (limited to 'llvm/lib/MC/WasmObjectWriter.cpp')
-rw-r--r-- | llvm/lib/MC/WasmObjectWriter.cpp | 360 |
1 files changed, 237 insertions, 123 deletions
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index 321f93d76092b..f51d908c53e13 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -27,6 +27,7 @@ #include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/StringSaver.h" @@ -107,7 +108,7 @@ struct WasmDataSegment { MCSectionWasm *Section; StringRef Name; uint32_t InitFlags; - uint32_t Offset; + uint64_t Offset; uint32_t Alignment; uint32_t LinkerFlags; SmallVector<char, 4> Data; @@ -152,7 +153,7 @@ struct WasmRelocationEntry { void print(raw_ostream &Out) const { Out << wasm::relocTypetoString(Type) << " Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend - << ", FixupSection=" << FixupSection->getSectionName(); + << ", FixupSection=" << FixupSection->getName(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -184,31 +185,37 @@ raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { // 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); +template <int W> +void writePatchableLEB(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) { + uint8_t Buffer[W]; + unsigned SizeLen = encodeULEB128(X, Buffer, W); + assert(SizeLen == W); 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); +template <int W> +void writePatchableSLEB(raw_pwrite_stream &Stream, int64_t X, uint64_t Offset) { + uint8_t Buffer[W]; + unsigned SizeLen = encodeSLEB128(X, Buffer, W); + assert(SizeLen == W); 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) { +static void patchI32(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 void patchI64(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) { + uint8_t Buffer[8]; + support::endian::write64le(Buffer, X); + Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset); +} + class WasmObjectWriter : public MCObjectWriter { support::endian::Writer W; @@ -217,11 +224,8 @@ class WasmObjectWriter : public MCObjectWriter { // Relocations for fixing up references in the code section. std::vector<WasmRelocationEntry> CodeRelocations; - uint32_t CodeSectionIndex; - // Relocations for fixing up references in the data section. std::vector<WasmRelocationEntry> DataRelocations; - uint32_t DataSectionIndex; // Index values to use for fixing up call_indirect type indices. // Maps function symbols to the index of the type of the function @@ -307,19 +311,32 @@ private: W.OS << Str; } + void writeI32(int32_t val) { + char Buffer[4]; + support::endian::write32le(Buffer, val); + W.OS.write(Buffer, sizeof(Buffer)); + } + + void writeI64(int64_t val) { + char Buffer[8]; + support::endian::write64le(Buffer, val); + W.OS.write(Buffer, sizeof(Buffer)); + } + void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); } void writeTypeSection(ArrayRef<WasmSignature> Signatures); - void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize, + void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint64_t DataSize, uint32_t NumElements); void writeFunctionSection(ArrayRef<WasmFunction> Functions); 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(); + uint32_t writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, + ArrayRef<WasmFunction> Functions); + uint32_t writeDataSection(const MCAsmLayout &Layout); void writeEventSection(ArrayRef<wasm::WasmEventType> Events); + void writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals); void writeRelocSection(uint32_t SectionIndex, StringRef Name, std::vector<WasmRelocationEntry> &Relocations); void writeLinkingMetaDataSection( @@ -333,9 +350,10 @@ private: updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions, const MCAsmLayout &Layout); - uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); + uint64_t getProvisionalValue(const WasmRelocationEntry &RelEntry, + const MCAsmLayout &Layout); void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, - uint64_t ContentsOffset); + uint64_t ContentsOffset, const MCAsmLayout &Layout); uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getFunctionType(const MCSymbolWasm &Symbol); @@ -396,8 +414,8 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) { // Write the final section size to the payload_len field, which follows // the section id byte. - writePatchableLEB(static_cast<raw_pwrite_stream &>(W.OS), Size, - Section.SizeOffset); + writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W.OS), Size, + Section.SizeOffset); } // Emit the Wasm header. @@ -417,7 +435,7 @@ void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S)); if (!Pair.second) report_fatal_error("section already has a defining function: " + - Sec.getSectionName()); + Sec.getName()); } } } @@ -436,10 +454,6 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); - // The .init_array isn't translated as data, so don't do relocations in it. - if (FixupSection.getSectionName().startswith(".init_array")) - return; - if (const MCSymbolRefExpr *RefB = Target.getSymB()) { // To get here the A - B expression must have failed evaluateAsRelocatable. // This means either A or B must be undefined and in WebAssembly we can't @@ -456,11 +470,17 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, const MCSymbolRefExpr *RefA = Target.getSymA(); const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol()); + // The .init_array isn't translated as data, so don't do relocations in it. + if (FixupSection.getName().startswith(".init_array")) { + SymA->setUsedInInitArray(); + return; + } + if (SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); - const auto *Inner = cast<MCSymbolRefExpr>(Expr); - if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) - llvm_unreachable("weakref used in reloc not yet implemented"); + if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) + if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) + llvm_unreachable("weakref used in reloc not yet implemented"); } // Put any constant offset in an addend. Offsets can be negative, and @@ -519,23 +539,16 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, } } -static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) { - const MCSymbolWasm* Ret = &Symbol; - while (Ret->isVariable()) { - const MCExpr *Expr = Ret->getVariableValue(); - auto *Inner = cast<MCSymbolRefExpr>(Expr); - Ret = cast<MCSymbolWasm>(&Inner->getSymbol()); - } - return Ret; -} - // Compute a value to write into the code at the location covered // by RelEntry. This value isn't used by the static linker; it just serves // to make the object format more readable and more likely to be directly // useable. -uint32_t -WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { - if (RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB && !RelEntry.Symbol->isGlobal()) { +uint64_t +WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry, + const MCAsmLayout &Layout) { + if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB || + RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) && + !RelEntry.Symbol->isGlobal()) { assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space"); return GOTIndices[RelEntry.Symbol]; } @@ -545,15 +558,20 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { 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); - assert(Sym->isFunction()); - return TableIndices[Sym]; + const MCSymbolWasm *Base = + cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol)); + assert(Base->isFunction()); + if (RelEntry.Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB) + return TableIndices[Base] - InitialTableOffset; + else + return TableIndices[Base]; } case wasm::R_WASM_TYPE_INDEX_LEB: // Provisional value is same as the index return getRelocationIndexValue(RelEntry); case wasm::R_WASM_FUNCTION_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_I32: case wasm::R_WASM_EVENT_INDEX_LEB: // Provisional value is function/global/event Wasm index assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space"); @@ -565,15 +583,20 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { return Section.getSectionOffset() + RelEntry.Addend; } case wasm::R_WASM_MEMORY_ADDR_LEB: - case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB64: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB64: case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: - case wasm::R_WASM_MEMORY_ADDR_SLEB: { + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_I64: { // Provisional value is address of the global - const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); + const MCSymbolWasm *Base = + cast<MCSymbolWasm>(Layout.getBaseSymbol(*RelEntry.Symbol)); // For undefined symbols, use zero - if (!Sym->isDefined()) + if (!Base->isDefined()) return 0; - const wasm::WasmDataReference &Ref = DataLocations[Sym]; + const wasm::WasmDataReference &Ref = DataLocations[Base]; const WasmDataSegment &Segment = DataSegments[Ref.Segment]; // Ignore overflow. LLVM allows address arithmetic to silently wrap. return Segment.Offset + Ref.Offset + RelEntry.Addend; @@ -585,7 +608,7 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { static void addData(SmallVectorImpl<char> &DataBytes, MCSectionWasm &DataSection) { - LLVM_DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); + LLVM_DEBUG(errs() << "addData: " << DataSection.getName() << "\n"); DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); @@ -636,7 +659,8 @@ WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) { // Apply the portions of the relocation records that we can handle ourselves // directly. void WasmObjectWriter::applyRelocations( - ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) { + ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset, + const MCAsmLayout &Layout) { auto &Stream = static_cast<raw_pwrite_stream &>(W.OS); for (const WasmRelocationEntry &RelEntry : Relocations) { uint64_t Offset = ContentsOffset + @@ -644,7 +668,7 @@ void WasmObjectWriter::applyRelocations( RelEntry.Offset; LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); - uint32_t Value = getProvisionalValue(RelEntry); + auto Value = getProvisionalValue(RelEntry, Layout); switch (RelEntry.Type) { case wasm::R_WASM_FUNCTION_INDEX_LEB: @@ -652,19 +676,30 @@ void WasmObjectWriter::applyRelocations( 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); + writePatchableLEB<5>(Stream, Value, Offset); + break; + case wasm::R_WASM_MEMORY_ADDR_LEB64: + writePatchableLEB<10>(Stream, Value, Offset); break; 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); + case wasm::R_WASM_GLOBAL_INDEX_I32: + patchI32(Stream, Value, Offset); + break; + case wasm::R_WASM_MEMORY_ADDR_I64: + patchI64(Stream, Value, Offset); break; 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); + writePatchableSLEB<5>(Stream, Value, Offset); + break; + case wasm::R_WASM_MEMORY_ADDR_SLEB64: + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: + writePatchableSLEB<10>(Stream, Value, Offset); break; default: llvm_unreachable("invalid relocation type"); @@ -695,12 +730,12 @@ void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) { } void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports, - uint32_t DataSize, + uint64_t DataSize, uint32_t NumElements) { if (Imports.empty()) return; - uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; + uint64_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_IMPORT); @@ -720,8 +755,8 @@ void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports, W.OS << char(Import.Global.Mutable ? 1 : 0); break; case wasm::WASM_EXTERNAL_MEMORY: - encodeULEB128(0, W.OS); // flags - encodeULEB128(NumPages, W.OS); // initial + encodeULEB128(Import.Memory.Flags, W.OS); + encodeULEB128(NumPages, W.OS); // initial break; case wasm::WASM_EXTERNAL_TABLE: W.OS << char(Import.Table.ElemType); @@ -770,6 +805,43 @@ void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) { endSection(Section); } +void WasmObjectWriter::writeGlobalSection(ArrayRef<wasm::WasmGlobal> Globals) { + if (Globals.empty()) + return; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_GLOBAL); + + encodeULEB128(Globals.size(), W.OS); + for (const wasm::WasmGlobal &Global : Globals) { + encodeULEB128(Global.Type.Type, W.OS); + W.OS << char(Global.Type.Mutable); + W.OS << char(Global.InitExpr.Opcode); + switch (Global.Type.Type) { + case wasm::WASM_TYPE_I32: + encodeSLEB128(0, W.OS); + break; + case wasm::WASM_TYPE_I64: + encodeSLEB128(0, W.OS); + break; + case wasm::WASM_TYPE_F32: + writeI32(0); + break; + case wasm::WASM_TYPE_F64: + writeI64(0); + break; + case wasm::WASM_TYPE_EXTERNREF: + writeValueType(wasm::ValType::EXTERNREF); + break; + default: + llvm_unreachable("unexpected type"); + } + W.OS << char(wasm::WASM_OPCODE_END); + } + + endSection(Section); +} + void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) { if (Exports.empty()) return; @@ -819,15 +891,14 @@ void WasmObjectWriter::writeDataCountSection() { endSection(Section); } -void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, - const MCAsmLayout &Layout, - ArrayRef<WasmFunction> Functions) { +uint32_t WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, + const MCAsmLayout &Layout, + ArrayRef<WasmFunction> Functions) { if (Functions.empty()) - return; + return 0; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CODE); - CodeSectionIndex = Section.Index; encodeULEB128(Functions.size(), W.OS); @@ -844,18 +915,18 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, } // Apply fixups. - applyRelocations(CodeRelocations, Section.ContentsOffset); + applyRelocations(CodeRelocations, Section.ContentsOffset, Layout); endSection(Section); + return Section.Index; } -void WasmObjectWriter::writeDataSection() { +uint32_t WasmObjectWriter::writeDataSection(const MCAsmLayout &Layout) { if (DataSegments.empty()) - return; + return 0; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_DATA); - DataSectionIndex = Section.Index; encodeULEB128(DataSegments.size(), W.OS); // count @@ -864,7 +935,9 @@ void WasmObjectWriter::writeDataSection() { 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); + W.OS << char(Segment.Offset > std::numeric_limits<int32_t>().max() + ? wasm::WASM_OPCODE_I64_CONST + : wasm::WASM_OPCODE_I32_CONST); encodeSLEB128(Segment.Offset, W.OS); // offset W.OS << char(wasm::WASM_OPCODE_END); } @@ -874,9 +947,10 @@ void WasmObjectWriter::writeDataSection() { } // Apply fixups. - applyRelocations(DataRelocations, Section.ContentsOffset); + applyRelocations(DataRelocations, Section.ContentsOffset, Layout); endSection(Section); + return Section.Index; } void WasmObjectWriter::writeRelocSection( @@ -1027,7 +1101,7 @@ void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection, // Apply fixups. auto &Relocations = CustomSectionsRelocations[CustomSection.Section]; - applyRelocations(Relocations, CustomSection.OutputContentsOffset); + applyRelocations(Relocations, CustomSection.OutputContentsOffset, Layout); } uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) { @@ -1046,8 +1120,8 @@ void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) { assert(Symbol.isFunction()); WasmSignature S; - const MCSymbolWasm *ResolvedSym = resolveSymbol(Symbol); - if (auto *Sig = ResolvedSym->getSignature()) { + + if (auto *Sig = Symbol.getSignature()) { S.Returns = Sig->Returns; S.Params = Sig->Params; } @@ -1084,16 +1158,13 @@ void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) { } static bool isInSymtab(const MCSymbolWasm &Sym) { - if (Sym.isUsedInReloc()) + if (Sym.isUsedInReloc() || Sym.isUsedInInitArray()) return true; if (Sym.isComdat() && !Sym.isDefined()) return false; - if (Sym.isTemporary() && Sym.getName().empty()) - return false; - - if (Sym.isTemporary() && Sym.isData() && !Sym.getSize()) + if (Sym.isTemporary()) return false; if (Sym.isSection()) @@ -1114,10 +1185,11 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, SmallVector<wasm::WasmImport, 4> Imports; SmallVector<wasm::WasmExport, 4> Exports; SmallVector<wasm::WasmEventType, 1> Events; + SmallVector<wasm::WasmGlobal, 1> Globals; SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; - uint32_t DataSize = 0; + uint64_t DataSize = 0; // 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 @@ -1126,6 +1198,8 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, MemImport.Module = "env"; MemImport.Field = "__linear_memory"; MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY; + MemImport.Memory.Flags = is64Bit() ? wasm::WASM_LIMITS_FLAG_IS_64 + : wasm::WASM_LIMITS_FLAG_NONE; Imports.push_back(MemImport); // For now, always emit the table section, since indirect calls are not @@ -1146,8 +1220,10 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Register types for all functions, including those with private linkage // (because wasm always needs a type signature). - if (WS.isFunction()) - registerFunctionType(WS); + if (WS.isFunction()) { + const MCSymbolWasm *Base = cast<MCSymbolWasm>(Layout.getBaseSymbol(S)); + registerFunctionType(*Base); + } if (WS.isEvent()) registerEventType(WS); @@ -1217,7 +1293,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // populating DataLocations. for (MCSection &Sec : Asm) { auto &Section = static_cast<MCSectionWasm &>(Sec); - StringRef SectionName = Section.getSectionName(); + StringRef SectionName = Section.getName(); // .init_array sections are handled specially elsewhere. if (SectionName.startswith(".init_array")) @@ -1365,30 +1441,53 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // For each data symbol, export it in the symtab as a reference to the // corresponding Wasm data segment. wasm::WasmDataReference Ref = wasm::WasmDataReference{ - DataSection.getSegmentIndex(), - static_cast<uint32_t>(Layout.getSymbolOffset(WS)), - static_cast<uint32_t>(Size)}; + DataSection.getSegmentIndex(), Layout.getSymbolOffset(WS), + static_cast<uint64_t>(Size)}; DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n"); } else if (WS.isGlobal()) { // A "true" Wasm global (currently just __stack_pointer) - if (WS.isDefined()) - report_fatal_error("don't yet support defined globals"); - - // An import; the index was assigned above - LLVM_DEBUG(dbgs() << " -> global index: " - << WasmIndices.find(&WS)->second << "\n"); - + if (WS.isDefined()) { + assert(WasmIndices.count(&WS) == 0); + wasm::WasmGlobal Global; + Global.Type = WS.getGlobalType(); + Global.Index = NumGlobalImports + Globals.size(); + switch (Global.Type.Type) { + case wasm::WASM_TYPE_I32: + Global.InitExpr.Opcode = wasm::WASM_OPCODE_I32_CONST; + break; + case wasm::WASM_TYPE_I64: + Global.InitExpr.Opcode = wasm::WASM_OPCODE_I64_CONST; + break; + case wasm::WASM_TYPE_F32: + Global.InitExpr.Opcode = wasm::WASM_OPCODE_F32_CONST; + break; + case wasm::WASM_TYPE_F64: + Global.InitExpr.Opcode = wasm::WASM_OPCODE_F64_CONST; + break; + case wasm::WASM_TYPE_EXTERNREF: + Global.InitExpr.Opcode = wasm::WASM_OPCODE_REF_NULL; + break; + default: + llvm_unreachable("unexpected type"); + } + WasmIndices[&WS] = Global.Index; + Globals.push_back(Global); + } else { + // An import; the index was assigned above + LLVM_DEBUG(dbgs() << " -> global index: " + << WasmIndices.find(&WS)->second << "\n"); + } } else if (WS.isEvent()) { // C++ exception symbol (__cpp_exception) unsigned Index; if (WS.isDefined()) { + assert(WasmIndices.count(&WS) == 0); Index = NumEventImports + Events.size(); 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 { @@ -1413,22 +1512,36 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, assert(S.isDefined()); + const MCSymbolWasm *Base = cast<MCSymbolWasm>(Layout.getBaseSymbol(S)); + // 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); - LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym - << "'\n"); + LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *Base << "'\n"); - if (ResolvedSym->isFunction()) { - assert(WasmIndices.count(ResolvedSym) > 0); - uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; + if (Base->isFunction()) { + assert(WasmIndices.count(Base) > 0); + uint32_t WasmIndex = WasmIndices.find(Base)->second; assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = WasmIndex; LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); - } else if (ResolvedSym->isData()) { - assert(DataLocations.count(ResolvedSym) > 0); - const wasm::WasmDataReference &Ref = - DataLocations.find(ResolvedSym)->second; + } else if (Base->isData()) { + auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection()); + uint64_t Offset = Layout.getSymbolOffset(S); + int64_t Size = 0; + // For data symbol alias we use the size of the base symbol as the + // size of the alias. When an offset from the base is involved this + // can result in a offset + size goes past the end of the data section + // which out object format doesn't support. So we must clamp it. + if (!Base->getSize()->evaluateAsAbsolute(Size, Layout)) + report_fatal_error(".size expression must be evaluatable"); + const WasmDataSegment &Segment = + DataSegments[DataSection.getSegmentIndex()]; + Size = + std::min(static_cast<uint64_t>(Size), Segment.Data.size() - Offset); + wasm::WasmDataReference Ref = wasm::WasmDataReference{ + DataSection.getSegmentIndex(), + static_cast<uint32_t>(Layout.getSymbolOffset(S)), + static_cast<uint32_t>(Size)}; DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); } else { @@ -1486,17 +1599,19 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // 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_WASM_TABLE_INDEX_I32 && - Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB) + Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB && + Rel.Type != wasm::R_WASM_TABLE_INDEX_REL_SLEB) return; assert(Rel.Symbol->isFunction()); - const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol); - uint32_t FunctionIndex = WasmIndices.find(&WS)->second; + const MCSymbolWasm *Base = + cast<MCSymbolWasm>(Layout.getBaseSymbol(*Rel.Symbol)); + uint32_t FunctionIndex = WasmIndices.find(Base)->second; uint32_t TableIndex = TableElems.size() + InitialTableOffset; - if (TableIndices.try_emplace(&WS, TableIndex).second) { - LLVM_DEBUG(dbgs() << " -> adding " << WS.getName() + if (TableIndices.try_emplace(Base, TableIndex).second) { + LLVM_DEBUG(dbgs() << " -> adding " << Base->getName() << " to table: " << TableIndex << "\n"); TableElems.push_back(FunctionIndex); - registerFunctionType(WS); + registerFunctionType(*Base); } }; @@ -1509,9 +1624,9 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Translate .init_array section contents into start functions. for (const MCSection &S : Asm) { const auto &WS = static_cast<const MCSectionWasm &>(S); - if (WS.getSectionName().startswith(".fini_array")) + if (WS.getName().startswith(".fini_array")) report_fatal_error(".fini_array sections are unsupported"); - if (!WS.getSectionName().startswith(".init_array")) + if (!WS.getName().startswith(".init_array")) continue; if (WS.getFragmentList().empty()) continue; @@ -1538,13 +1653,11 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, uint16_t Priority = UINT16_MAX; unsigned PrefixLength = strlen(".init_array"); - if (WS.getSectionName().size() > PrefixLength) { - if (WS.getSectionName()[PrefixLength] != '.') + if (WS.getName().size() > PrefixLength) { + if (WS.getName()[PrefixLength] != '.') report_fatal_error( ".init_array section priority should start with '.'"); - if (WS.getSectionName() - .substr(PrefixLength + 1) - .getAsInteger(10, Priority)) + if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority)) report_fatal_error("invalid .init_array section priority"); } const auto &DataFrag = cast<MCDataFragment>(Frag); @@ -1565,7 +1678,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error("fixups in .init_array should be symbol references"); const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol()); if (TargetSym.getIndex() == InvalidIndex) - report_fatal_error("symbols in .init_array should exist in symbtab"); + report_fatal_error("symbols in .init_array should exist in symtab"); if (!TargetSym.isFunction()) report_fatal_error("symbols in .init_array should be for functions"); InitFuncs.push_back( @@ -1582,11 +1695,12 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm, // Skip the "table" section; we import the table instead. // Skip the "memory" section; we import the memory instead. writeEventSection(Events); + writeGlobalSection(Globals); writeExportSection(Exports); writeElemSection(TableElems); writeDataCountSection(); - writeCodeSection(Asm, Layout, Functions); - writeDataSection(); + uint32_t CodeSectionIndex = writeCodeSection(Asm, Layout, Functions); + uint32_t DataSectionIndex = writeDataSection(Layout); for (auto &CustomSection : CustomSections) writeCustomSection(CustomSection, Asm, Layout); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); |