Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -223,7 +223,7 @@ } void startSection(SectionBookkeeping &Section, unsigned SectionId, - const char *Name = nullptr); + Optional Name = Optional()); void endSection(SectionBookkeeping &Section); public: @@ -286,6 +286,11 @@ ArrayRef> SymbolFlags, ArrayRef> InitFuncs, const std::map>& Comdats); + void writeUserCustomSections(const + std::vector*>>& + CustomSections); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, @@ -304,11 +309,14 @@ // Write out a section header and a patchable section size field. void WasmObjectWriter::startSection(SectionBookkeeping &Section, unsigned SectionId, - const char *Name) { - assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && + Optional Name) { + assert((Name.hasValue()) == (SectionId == wasm::WASM_SEC_CUSTOM) && "Only custom sections can have names"); - DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); + DEBUG(dbgs() << "startSection " << SectionId; + if (Name.hasValue()) + dbgs() << ": " << Name.getValue(); + dbgs() << "\n"); encodeULEB128(SectionId, getStream()); Section.SizeOffset = getStream().tell(); @@ -322,8 +330,7 @@ // Custom sections in wasm also have a string identifier. if (SectionId == wasm::WASM_SEC_CUSTOM) { - assert(Name); - writeString(StringRef(Name)); + writeString(Name.getValue()); } } @@ -837,7 +844,7 @@ return; SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE"); + startSection(Section, wasm::WASM_SEC_CUSTOM, StringRef("reloc.CODE")); encodeULEB128(wasm::WASM_SEC_CODE, getStream()); encodeULEB128(CodeRelocations.size(), getStream()); @@ -855,7 +862,7 @@ return; SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA"); + startSection(Section, wasm::WASM_SEC_CUSTOM, StringRef("reloc.DATA")); encodeULEB128(wasm::WASM_SEC_DATA, getStream()); encodeULEB128(DataRelocations.size(), getStream()); @@ -871,7 +878,7 @@ ArrayRef> InitFuncs, const std::map>& Comdats) { SectionBookkeeping Section; - startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); + startSection(Section, wasm::WASM_SEC_CUSTOM, StringRef("linking")); SectionBookkeeping SubSection; if (SymbolFlags.size() != 0) { @@ -929,6 +936,19 @@ endSection(Section); } +void WasmObjectWriter::writeUserCustomSections( + const std::vector*>>& + CustomSections +) { + for (const auto &CustomSection : CustomSections) { + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_CUSTOM, CustomSection.first); + writeBytes(*CustomSection.second); + endSection(Section); + } +} + uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); @@ -969,6 +989,8 @@ SmallVector, 2> InitFuncs; std::map> Comdats; SmallVector DataSegments; + std::vector*>> + CustomSections; uint32_t DataSize = 0; // For now, always emit the memory import, since loads and stores are not @@ -1037,6 +1059,24 @@ for (MCSection &Sec : Asm) { auto &Section = static_cast(Sec); + + if (cast(Sec).getSectionName().startswith(".custom_section.")) { + if (Section.getFragmentList().empty()) + continue; + if (Section.getFragmentList().size() != 1) + report_fatal_error("only one .custom_section section fragment supported"); + const MCFragment &Frag = *Section.begin(); + if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) + report_fatal_error("only data supported in .custom_section section"); + const auto &DataFrag = cast(Frag); + if (!DataFrag.getFixups().empty()) + report_fatal_error("fixups not supported in .custom_section section"); + const SmallVectorImpl &Contents = DataFrag.getContents(); + StringRef UserName = Section.getSectionName().substr(16); + CustomSections.push_back(std::make_pair(UserName, &Contents)); + continue; + } + if (!Section.isWasmData()) continue; @@ -1294,6 +1334,7 @@ writeDataRelocSection(); writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, InitFuncs, Comdats); + writeUserCustomSections(CustomSections); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. Index: lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -32,6 +32,7 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MCSymbolELF.h" @@ -99,6 +100,26 @@ } } } + + if (const NamedMDNode* Named = M.getNamedMetadata("wasm.custom_sections")) { + for (const Metadata *MD : Named->operands()) { + const MDTuple *Tuple = dyn_cast(MD); + if (!Tuple || Tuple->getNumOperands() != 2) + continue; + const MDString *Name = dyn_cast(Tuple->getOperand(0)); + const MDString *Contents = dyn_cast(Tuple->getOperand(1)); + if (!Name || !Contents) + continue; + + OutStreamer->PushSection(); + std::string SectionName = (".custom_section." + Name->getString()).str(); + MCSectionWasm *mySection = + OutContext.getWasmSection(SectionName, SectionKind::getMetadata()); + OutStreamer->SwitchSection(mySection); + OutStreamer->EmitBytes(Contents->getString()); + OutStreamer->PopSection(); + } + } } void WebAssemblyAsmPrinter::EmitConstantPool() { Index: test/CodeGen/WebAssembly/custom-sections.ll =================================================================== --- test/CodeGen/WebAssembly/custom-sections.ll +++ test/CodeGen/WebAssembly/custom-sections.ll @@ -0,0 +1,20 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s + +; Test the mechanism for defining user custom sections. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +!0 = !{ !"red", !"foo" } +!1 = !{ !"green", !"bar" } +!2 = !{ !"green", !"qux" } +!wasm.custom_sections = !{ !0, !1, !2 } + +; CHECK: .section .custom_section.red,"",@ +; CHECK-NEXT: .ascii "foo" + +; CHECK: .section .custom_section.green,"",@ +; CHECK-NEXT: .ascii "bar" + +; CHECK: .section .custom_section.green,"",@ +; CHECK-NEXT: .ascii "qux"