Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -167,6 +167,14 @@ #endif }; +struct WasmCustomSection { + StringRef Name; + const SmallVectorImpl &Contents; + + WasmCustomSection(StringRef Name, const SmallVectorImpl &Contents) + : Name(Name), Contents(Contents) {} +}; + #if !defined(NDEBUG) raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { Rel.print(OS); @@ -202,6 +210,7 @@ SmallVector FunctionTypes; SmallVector Globals; SmallVector DataSegments; + std::vector CustomSections; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; @@ -212,7 +221,7 @@ } void startSection(SectionBookkeeping &Section, unsigned SectionId, - const char *Name = nullptr); + const char* Name = nullptr); void endSection(SectionBookkeeping &Section); public: @@ -277,6 +286,8 @@ ArrayRef SymbolInfos, ArrayRef> InitFuncs, const std::map> &Comdats); + void writeUserCustomSections( + const std::vector &CustomSections); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, @@ -313,8 +324,7 @@ // Custom sections in wasm also have a string identifier. if (SectionId == wasm::WASM_SEC_CUSTOM) { - assert(Name); - writeString(StringRef(Name)); + writeString(Name); } } @@ -936,6 +946,17 @@ endSection(Section); } +void WasmObjectWriter::writeUserCustomSections( + const std::vector &CustomSections +) { + for (const auto &CustomSection : CustomSections) { + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_CUSTOM, CustomSection.Name.str().c_str()); + writeBytes(CustomSection.Contents); + endSection(Section); + } +} + uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); @@ -1041,6 +1062,24 @@ // Populate DataSegments, which must be done before populating DataLocations. 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"); + StringRef UserName = Section.getSectionName().substr(16); + const SmallVectorImpl &Contents = DataFrag.getContents(); + CustomSections.push_back(WasmCustomSection(UserName, Contents)); + continue; + } + if (!Section.isWasmData()) continue; @@ -1310,6 +1349,7 @@ writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); writeDataSection(); + writeUserCustomSections(CustomSections); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); writeCodeRelocSection(); writeDataRelocSection(); 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" @@ -107,6 +108,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 =================================================================== --- /dev/null +++ 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" Index: test/MC/WebAssembly/custom-sections.ll =================================================================== --- /dev/null +++ test/MC/WebAssembly/custom-sections.ll @@ -0,0 +1,23 @@ +; RUN: llc -filetype=obj %s -o - | llvm-readobj -s | FileCheck %s + +; Test the mechanism for defining user custom sections. + +target triple = "wasm32-unknown-unknown-wasm" + +!0 = !{ !"red", !"foo" } +!1 = !{ !"green", !"bar" } +!2 = !{ !"green", !"qux" } +!wasm.custom_sections = !{ !0, !1, !2 } + +; CHECK: Section { +; CHECK: Type: CUSTOM (0x0) +; CHECK: Size: 7 +; CHECK: Offset: 72 +; CHECK: Name: red +; CHECK: } +; CHECK: Section { +; CHECK: Type: CUSTOM (0x0) +; CHECK: Size: 12 +; CHECK: Offset: 85 +; CHECK: Name: green +; CHECK: }