Index: include/llvm/BinaryFormat/Wasm.h =================================================================== --- include/llvm/BinaryFormat/Wasm.h +++ include/llvm/BinaryFormat/Wasm.h @@ -140,6 +140,11 @@ uint32_t Symbol; }; +struct WasmSectionCodeAndName { + uint32_t Code; + StringRef Name; +}; + struct WasmSymbolInfo { StringRef Name; uint8_t Kind; @@ -151,6 +156,8 @@ // For a data symbols, the address of the data relative to segment. WasmDataReference DataRef; }; + // FIXME For section symbols, the section code and, if custom, its name. + WasmSectionCodeAndName Section; }; struct WasmFunctionName { @@ -244,6 +251,7 @@ WASM_SYMBOL_TYPE_FUNCTION = 0x0, WASM_SYMBOL_TYPE_DATA = 0x1, WASM_SYMBOL_TYPE_GLOBAL = 0x2, + WASM_SYMBOL_TYPE_SECTION = 0x3, }; const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; Index: include/llvm/BinaryFormat/WasmRelocs.def =================================================================== --- include/llvm/BinaryFormat/WasmRelocs.def +++ include/llvm/BinaryFormat/WasmRelocs.def @@ -11,3 +11,5 @@ WASM_RELOC(R_WEBASSEMBLY_MEMORY_ADDR_I32, 5) WASM_RELOC(R_WEBASSEMBLY_TYPE_INDEX_LEB, 6) WASM_RELOC(R_WEBASSEMBLY_GLOBAL_INDEX_LEB, 7) +WASM_RELOC(R_WEBASSEMBLY_FUNCTION_OFFSET_I32, 8) +WASM_RELOC(R_WEBASSEMBLY_SECTION_OFFSET_I32, 9) Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -48,7 +48,9 @@ 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; }; @@ -131,6 +133,15 @@ uint32_t Index; }; +// Information to store symbols that point to Wasm sections content offsets. +struct WasmSectionEntry { + const MCSymbolWasm *Sym; + const MCSection* Section; + + WasmSectionEntry(const MCSymbolWasm *Sym, const MCSection* Section) + : Sym(Sym), Section(Section) {} +}; + // Information about a single relocation. struct WasmRelocationEntry { uint64_t Offset; // Where is the relocation. @@ -150,6 +161,8 @@ 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; @@ -184,6 +197,9 @@ // Relocations for fixing up references in the data section. std::vector DataRelocations; + // Relocations for fixing up references in the custom sections. + StringMap< std::vector > CustomSectionsRelocations; + // Index values to use for fixing up call_indirect type indices. // Maps function symbols to the index of the type of the function DenseMap TypeIndices; @@ -196,6 +212,8 @@ DenseMap WasmIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. DenseMap DataLocations; + // Maps section symbols to the section. + DenseMap CustomSections; DenseMap FunctionTypeIndices; @@ -227,11 +245,13 @@ void reset() override { CodeRelocations.clear(); DataRelocations.clear(); + CustomSectionsRelocations.clear(); TypeIndices.clear(); SymbolIndices.clear(); WasmIndices.clear(); TableIndices.clear(); DataLocations.clear(); + CustomSections.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); Globals.clear(); @@ -273,11 +293,16 @@ void writeDataSection(); void writeCodeRelocSection(); void writeDataRelocSection(); + void writeDebugRelocSections(); void writeLinkingMetaDataSection( ArrayRef SymbolInfos, ArrayRef> InitFuncs, const std::map> &Comdats); + void writeDebugSections(const MCAssembler &Asm, + const MCAsmLayout &Layout); + void updateCustomSectionRelocations( + const SmallVector &Functions); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, uint64_t ContentsOffset); @@ -308,20 +333,23 @@ // for any 32-bit value; we'll patch it later. encodeULEB128(UINT32_MAX, getStream()); - // The position where the section starts, for measuring its size. - Section.ContentsOffset = getStream().tell(); + // The position where the section header ends, for measuring its size. + Section.PayloadOffset = getStream().tell(); // Custom sections in wasm also have a string identifier. if (SectionId == wasm::WASM_SEC_CUSTOM) { assert(Name); writeString(StringRef(Name)); } + + // The position where the 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"); @@ -362,9 +390,13 @@ if (FixupSection.getSectionName().startswith(".init_array")) return; - // TODO(sbc): Add support for debug sections. - if (FixupSection.getKind().isMetadata()) - return; + bool IsDebugFixup = false; + // TODO: Add support for non-debug metadata sections? + if (FixupSection.getKind().isMetadata()) { + if (!FixupSection.getSectionName().startswith(".debug_")) + return; + IsDebugFixup = true; + } if (const MCSymbolRefExpr *RefB = Target.getSymB()) { assert(RefB->getKind() == MCSymbolRefExpr::VK_None && @@ -434,6 +466,27 @@ WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); + if (IsDebugFixup) { + switch (Type) { + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + break; + default: + report_fatal_error("relocation in debug section supported only for " + "R_WEBASSEMBLY_MEMORY_ADDR_I32 or _OFFSET_I32"); + } + + const auto& FixupSectionName = FixupSection.getSectionName().str(); + auto Relocs = CustomSectionsRelocations.find(FixupSectionName); + if (Relocs == CustomSectionsRelocations.end()) { + CustomSectionsRelocations[FixupSectionName] = std::vector(); + Relocs = CustomSectionsRelocations.find(FixupSectionName); + } + Relocs->second.push_back(Rec); + return; + } + // Relocation other than R_WEBASSEMBLY_TYPE_INDEX_LEB are currently required // to be against a named symbol. // TODO(sbc): Add support for relocations against unnamed temporaries such @@ -511,6 +564,14 @@ 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(RelEntry.Symbol->getSection()); + return Section.getSectionOffset() + RelEntry.Addend; + } + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + const auto &Section = *CustomSections.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: { @@ -602,6 +663,8 @@ 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: @@ -861,6 +924,24 @@ endSection(Section); } +void WasmObjectWriter::writeDebugRelocSections() { + for (const auto& P: CustomSectionsRelocations) { + auto CustomSectionName = P.first(); + auto DebugRelocations = P.second; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_CUSTOM, ("reloc." + CustomSectionName).str().c_str()); + + encodeULEB128(wasm::WASM_SEC_CUSTOM, getStream()); + writeString(CustomSectionName); + encodeULEB128(DebugRelocations.size(), getStream()); + + writeRelocations(DebugRelocations); + + endSection(Section); + } +} + void WasmObjectWriter::writeLinkingMetaDataSection( ArrayRef SymbolInfos, ArrayRef> InitFuncs, @@ -890,6 +971,11 @@ encodeULEB128(Sym.DataRef.Size, getStream()); } break; + case wasm::WASM_SYMBOL_TYPE_SECTION: + encodeULEB128(Sym.Section.Code, getStream()); + if (Sym.Section.Code == wasm::WASM_SEC_CUSTOM) + writeString(Sym.Section.Name); + break; default: llvm_unreachable("unexpected kind"); } @@ -936,6 +1022,60 @@ endSection(Section); } +void WasmObjectWriter::writeDebugSections(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + for (MCSection &Sec : Asm) { + auto &DebugSection = static_cast(Sec); + StringRef SectionName = DebugSection.getSectionName(); + + if (!SectionName.startswith(".debug_")) + continue; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_CUSTOM, SectionName.str().c_str()); + + DebugSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); + Asm.writeSectionData(&DebugSection, Layout); + + endSection(Section); + } +} + +void WasmObjectWriter::updateCustomSectionRelocations( + const SmallVector &Functions) { + std::map SectionSymbols; + for (const auto& P: CustomSections) + SectionSymbols[P.second] = P.first; + std::map 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. + for (auto& P: CustomSectionsRelocations) { + for (WasmRelocationEntry& RelEntry: P.second) { + switch (RelEntry.Type) { + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: { + assert(RelEntry.hasAddend()); + auto& Section = static_cast(RelEntry.Symbol->getSection()); + RelEntry.Symbol = FuncSymbols[&Section]; + RelEntry.Addend += Section.getSectionOffset(); + break; + } + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + assert(RelEntry.hasAddend()); + auto& Section = static_cast(RelEntry.Symbol->getSection()); + RelEntry.Symbol = SectionSymbols[&Section]; + RelEntry.Addend += Section.getSectionOffset(); + break; + } + default: + break; + } + } + } +} + uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); @@ -1064,6 +1204,28 @@ } } + // Create symbols for debug/custom sections. + for (const MCSection &Sec : Asm) { + const auto &DebugSection = static_cast(Sec); + StringRef SectionName = DebugSection.getSectionName(); + + if (!SectionName.startswith(".debug_")) + continue; + + auto SymbolName = (".Lsection_start" + SectionName).str(); + MCSymbolWasm *SectionSym = cast(Ctx.getOrCreateSymbol(SymbolName)); + CustomSections[SectionSym] = &DebugSection; + + wasm::WasmSymbolInfo Info; + Info.Name = SectionSym->getName(); + Info.Kind = wasm::WASM_SYMBOL_TYPE_SECTION; + Info.Flags = 0; + Info.Section.Code = wasm::WASM_SEC_CUSTOM; + Info.Section.Name = SectionName; + 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, @@ -1307,12 +1469,14 @@ writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); writeDataSection(); + writeDebugSections(Asm, Layout); + updateCustomSectionRelocations(Functions); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); writeCodeRelocSection(); writeDataRelocSection(); + writeDebugRelocSections(); // TODO: Translate the .comment section to the output. - // TODO: Translate debug sections to the output. } std::unique_ptr Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -21,6 +21,7 @@ #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Casting.h" @@ -61,6 +62,22 @@ return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX; } +static const MCSection* GetFixupSection(const MCExpr *Expr) { + if (auto SyExp = dyn_cast(Expr)) + return &SyExp->getSymbol().getSection(); + + if (auto BinOp = dyn_cast(Expr)) { + auto SectionLHS = GetFixupSection(BinOp->getLHS()); + auto SectionRHS = GetFixupSection(BinOp->getRHS()); + return SectionLHS == SectionRHS ? nullptr : SectionLHS; + } + + if (auto UnOp = dyn_cast(Expr)) + return GetFixupSection(UnOp->getSubExpr()); + + return nullptr; +} + unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, const MCFixup &Fixup) const { @@ -86,6 +103,12 @@ case FK_Data_4: if (IsFunction) return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32; + if (auto Section = static_cast(GetFixupSection(Fixup.getValue()))) { + if (Section->getKind().isText()) + return wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32; + else if (!Section->isWasmData()) + return wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32; + } return wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32; case FK_Data_8: llvm_unreachable("FK_Data_8 not implemented yet");