diff options
Diffstat (limited to 'llvm/lib/MC/WasmObjectWriter.cpp')
-rw-r--r-- | llvm/lib/MC/WasmObjectWriter.cpp | 189 |
1 files changed, 164 insertions, 25 deletions
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index 0e122708504..88bd046ec6e 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -48,7 +48,9 @@ static const uint32_t kInitialTableOffset = 1; struct SectionBookkeeping { // Where the size of the section is written. uint64_t SizeOffset; - // Where the contents of the section starts (after the header). + // Where the section header ends (without custom section name). + uint64_t PayloadOffset; + // Where the contents of the section starts. uint64_t ContentsOffset; uint32_t Index; }; @@ -151,6 +153,8 @@ struct WasmRelocationEntry { 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; @@ -169,11 +173,17 @@ struct WasmRelocationEntry { }; struct WasmCustomSection { + const uint32_t INVALID_INDEX = -1; + StringRef Name; - const SmallVectorImpl<char> &Contents; + MCSectionWasm *Section; + + uint32_t OutputContentsOffset; + uint32_t OutputIndex; - WasmCustomSection(StringRef Name, const SmallVectorImpl<char> &Contents) - : Name(Name), Contents(Contents) {} + WasmCustomSection(StringRef Name, MCSectionWasm *Section) + : Name(Name), Section(Section), OutputContentsOffset(0), + OutputIndex(INVALID_INDEX) {} }; #if !defined(NDEBUG) @@ -207,13 +217,21 @@ class WasmObjectWriter : public MCObjectWriter { DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; + // Maps section symbols to the section. + DenseMap<const MCSymbolWasm *, const MCSectionWasm *> CustomSectionSymbols; + + // Stores output data (index, relocations, content offset) for custom + // section. + std::vector<WasmCustomSection> CustomSections; + // Relocations for fixing up references in the custom sections. + DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>> + CustomSectionsRelocations; DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> FunctionTypeIndices; SmallVector<WasmFunctionType, 4> FunctionTypes; SmallVector<WasmGlobal, 4> Globals; SmallVector<WasmDataSegment, 4> DataSegments; - std::vector<WasmCustomSection> CustomSections; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; uint32_t SectionCount = 0; @@ -245,10 +263,12 @@ private: WasmIndices.clear(); TableIndices.clear(); DataLocations.clear(); + CustomSectionsRelocations.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); Globals.clear(); DataSegments.clear(); + CustomSectionSymbols.clear(); MCObjectWriter::reset(); NumFunctionImports = 0; NumGlobalImports = 0; @@ -290,7 +310,11 @@ private: ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats); - void writeUserCustomSections(ArrayRef<WasmCustomSection> CustomSections); + void writeCustomSections(const MCAssembler &Asm, const MCAsmLayout &Layout); + void writeCustomRelocSections(); + void + updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions, + const MCAsmLayout &Layout); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, @@ -319,6 +343,7 @@ void WasmObjectWriter::startSection(SectionBookkeeping &Section, // The position where the section starts, for measuring its size. Section.ContentsOffset = getStream().tell(); + Section.PayloadOffset = getStream().tell(); Section.Index = SectionCount++; } @@ -326,14 +351,21 @@ void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section, StringRef Name) { DEBUG(dbgs() << "startCustomSection " << Name << "\n"); startSection(Section, wasm::WASM_SEC_CUSTOM); + + // The position where the section header ends, for measuring its size. + Section.PayloadOffset = getStream().tell(); + // Custom sections in wasm also have a string identifier. writeString(Name); + + // The position where the custom section starts. + Section.ContentsOffset = getStream().tell(); } // 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 = getStream().tell() - Section.ContentsOffset; + uint64_t Size = getStream().tell() - Section.PayloadOffset; if (uint32_t(Size) != Size) report_fatal_error("section size does not fit in a uint32_t"); @@ -374,8 +406,9 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, if (FixupSection.getSectionName().startswith(".init_array")) return; - // TODO(sbc): Add support for debug sections. - if (FixupSection.getKind().isMetadata()) + // TODO: Add support for non-debug metadata sections? + if (FixupSection.getKind().isMetadata() && + !FixupSection.getSectionName().startswith(".debug_")) return; if (const MCSymbolRefExpr *RefB = Target.getSymB()) { @@ -446,21 +479,29 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); - // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required - // to be against a named symbol. + // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB, + // R_WEBASSEMBLY_SECTION_OFFSET_I32 or R_WEBASSEMBLY_FUNCTION_OFFSET_I32 + // are currently required to be against a named symbol. // TODO(sbc): Add support for relocations against unnamed temporaries such // as those generated by llvm's `blockaddress`. // See: test/MC/WebAssembly/blockaddress.ll - if (SymA->getName().empty() && Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) + if (SymA->getName().empty() && + !(Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB || + Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32 || + Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32)) report_fatal_error("relocations against un-named temporaries are not yet " "supported by wasm"); - if (FixupSection.isWasmData()) + if (FixupSection.isWasmData()) { DataRelocations.push_back(Rec); - else if (FixupSection.getKind().isText()) + } else if (FixupSection.getKind().isText()) { CodeRelocations.push_back(Rec); - else + } else if (FixupSection.getKind().isMetadata()) { + assert(FixupSection.getSectionName().startswith(".debug_")); + CustomSectionsRelocations[&FixupSection].push_back(Rec); + } else { llvm_unreachable("unexpected section type"); + } } // Write X as an (unsigned) LEB value at offset Offset in Stream, padded @@ -523,6 +564,15 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { report_fatal_error("symbol not found in wasm index space: " + RelEntry.Symbol->getName()); return WasmIndices[RelEntry.Symbol]; + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: { + const auto &Section = + static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection()); + return Section.getSectionOffset() + RelEntry.Addend; + } + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + const auto &Section = *CustomSectionSymbols.find(RelEntry.Symbol)->second; + 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: { @@ -614,6 +664,8 @@ void WasmObjectWriter::applyRelocations( 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); break; case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: @@ -851,6 +903,13 @@ void WasmObjectWriter::writeRelocSection( endSection(Section); } +void WasmObjectWriter::writeCustomRelocSections() { + for (const auto &Sec : CustomSections) { + auto &Relocations = CustomSectionsRelocations[Sec.Section]; + writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations); + } +} + void WasmObjectWriter::writeLinkingMetaDataSection( ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, @@ -881,6 +940,12 @@ void WasmObjectWriter::writeLinkingMetaDataSection( encodeULEB128(Sym.DataRef.Size, getStream()); } break; + case wasm::WASM_SYMBOL_TYPE_SECTION: { + const uint32_t SectionIndex = + CustomSections[Sym.ElementIndex].OutputIndex; + encodeULEB128(SectionIndex, getStream()); + break; + } default: llvm_unreachable("unexpected kind"); } @@ -927,16 +992,66 @@ void WasmObjectWriter::writeLinkingMetaDataSection( endSection(Section); } -void WasmObjectWriter::writeUserCustomSections( - ArrayRef<WasmCustomSection> CustomSections) { - for (const auto &CustomSection : CustomSections) { +void WasmObjectWriter::writeCustomSections(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + for (auto &CustomSection : CustomSections) { SectionBookkeeping Section; + auto *Sec = CustomSection.Section; startCustomSection(Section, CustomSection.Name); - writeBytes(CustomSection.Contents); + + Sec->setSectionOffset(getStream().tell() - Section.ContentsOffset); + Asm.writeSectionData(Sec, Layout); + + CustomSection.OutputContentsOffset = Section.ContentsOffset; + CustomSection.OutputIndex = Section.Index; + endSection(Section); } } +void WasmObjectWriter::updateCustomSectionRelocations( + const SmallVector<WasmFunction, 4> &Functions, const MCAsmLayout &Layout) { + std::map<const MCSection *, const MCSymbolWasm *> SectionSymbols; + for (const auto &P : CustomSectionSymbols) + SectionSymbols[P.second] = P.first; + std::map<const MCSection *, const MCSymbolWasm *> FuncSymbols; + for (const auto &FuncInfo : Functions) + FuncSymbols[&FuncInfo.Sym->getSection()] = FuncInfo.Sym; + + // Patch relocation records for R_WEBASSEMBLY_FUNCTION_OFFSET_I32 and + // R_WEBASSEMBLY_SECTION_OFFSET_I32. The Addend is stuffed the offset from + // the beginning of the function or custom section -- all such relocations + // target the function or custom section starts. + for (auto &Section : CustomSections) { + auto &Relocations = CustomSectionsRelocations[Section.Section]; + for (WasmRelocationEntry &RelEntry : Relocations) { + switch (RelEntry.Type) { + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: { + assert(RelEntry.hasAddend()); + auto &Section = + static_cast<MCSectionWasm &>(RelEntry.Symbol->getSection()); + RelEntry.Addend += Layout.getSymbolOffset(*RelEntry.Symbol); + RelEntry.Symbol = FuncSymbols[&Section]; + break; + } + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + assert(RelEntry.hasAddend()); + auto &Section = + static_cast<MCSectionWasm &>(RelEntry.Symbol->getSection()); + RelEntry.Addend += Layout.getSymbolOffset(*RelEntry.Symbol); + RelEntry.Symbol = SectionSymbols[&Section]; + break; + } + default: + break; + } + } + + // Apply fixups. + applyRelocations(Relocations, Section.OutputContentsOffset); + } +} + uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); @@ -1043,8 +1158,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, for (MCSection &Sec : Asm) { auto &Section = static_cast<MCSectionWasm &>(Sec); - if (cast<MCSectionWasm>(Sec).getSectionName().startswith( - ".custom_section.")) { + if (Section.getSectionName().startswith(".custom_section.")) { if (Section.getFragmentList().empty()) continue; if (Section.getFragmentList().size() != 1) @@ -1057,8 +1171,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!DataFrag.getFixups().empty()) report_fatal_error("fixups not supported in .custom_section section"); StringRef UserName = Section.getSectionName().substr(16); - const SmallVectorImpl<char> &Contents = DataFrag.getContents(); - CustomSections.push_back(WasmCustomSection(UserName, Contents)); + CustomSections.emplace_back(UserName, &Section); continue; } @@ -1088,6 +1201,31 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, } } + // Create symbols for debug/custom sections. + for (MCSection &Sec : Asm) { + auto &DebugSection = static_cast<MCSectionWasm &>(Sec); + StringRef SectionName = DebugSection.getSectionName(); + + // TODO: Add support for non-debug metadata sections? + if (!Sec.getKind().isMetadata() || !SectionName.startswith(".debug_")) + continue; + + uint32_t ElementIndex = CustomSections.size(); + CustomSections.emplace_back(SectionName, &DebugSection); + + MCSymbolWasm *SectionSym = + cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SectionName)); + CustomSectionSymbols[SectionSym] = &DebugSection; + + wasm::WasmSymbolInfo Info; + Info.Name = SectionSym->getName(); + Info.Kind = wasm::WASM_SYMBOL_TYPE_SECTION; + Info.Flags = 0; + Info.ElementIndex = ElementIndex; + SymbolIndices[SectionSym] = SymbolInfos.size(); + SymbolInfos.emplace_back(Info); + } + // Populate WasmIndices and DataLocations for defined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, @@ -1331,13 +1469,14 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); writeDataSection(); - writeUserCustomSections(CustomSections); + writeCustomSections(Asm, Layout); + updateCustomSectionRelocations(Functions, Layout); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations); writeRelocSection(DataSectionIndex, "DATA", DataRelocations); + writeCustomRelocSections(); // TODO: Translate the .comment section to the output. - // TODO: Translate debug sections to the output. } std::unique_ptr<MCObjectWriter> |