Index: include/llvm/BinaryFormat/Wasm.h =================================================================== --- include/llvm/BinaryFormat/Wasm.h +++ include/llvm/BinaryFormat/Wasm.h @@ -150,7 +150,11 @@ uint32_t ElementIndex; // For a data symbols, the address of the data relative to segment. WasmDataReference DataRef; + // For a section symbols, the code of the section (see also SectionName). + uint32_t SectionCode; }; + // Present for a section symbols, when code is a custom section. + StringRef SectionName; }; struct WasmFunctionName { @@ -245,8 +249,9 @@ // Kind codes used in the custom "linking" section in the WASM_SYMBOL_TABLE enum WasmSymbolType : unsigned { WASM_SYMBOL_TYPE_FUNCTION = 0x0, - WASM_SYMBOL_TYPE_DATA = 0x1, - WASM_SYMBOL_TYPE_GLOBAL = 0x2, + 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: include/llvm/Object/RelocVisitor.h =================================================================== --- include/llvm/Object/RelocVisitor.h +++ include/llvm/Object/RelocVisitor.h @@ -23,6 +23,7 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include @@ -46,6 +47,8 @@ return visitCOFF(Rel, R, Value); if (isa(ObjToVisit)) return visitMachO(Rel, R, Value); + if (isa(ObjToVisit)) + return visitWasm(Rel, R, Value); HasError = true; return 0; @@ -316,6 +319,29 @@ HasError = true; return 0; } + + uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) { + if (ObjToVisit.getArch() == Triple::wasm32) { + switch (Rel) { + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + 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_TYPE_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + // For wasm section, its offset at 0 -- ignoring Value + // TODO do we want to use absolute section offset in the wasm file? + HasError = false; + return 0; + } + } + HasError = true; + return 0; + } }; } // end namespace object Index: include/llvm/Object/Wasm.h =================================================================== --- include/llvm/Object/Wasm.h +++ include/llvm/Object/Wasm.h @@ -53,6 +53,10 @@ return Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL; } + bool isTypeSection() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION; + } + bool isDefined() const { return !isUndefined(); } bool isUndefined() const { @@ -206,6 +210,7 @@ bool isValidFunctionSymbol(uint32_t Index) const; bool isValidGlobalSymbol(uint32_t Index) const; bool isValidDataSymbol(uint32_t Index) const; + bool isValidSectionSymbol(uint32_t Index) const; wasm::WasmFunction &getDefinedFunction(uint32_t Index); wasm::WasmGlobal &getDefinedGlobal(uint32_t Index); Index: include/llvm/ObjectYAML/WasmYAML.h =================================================================== --- include/llvm/ObjectYAML/WasmYAML.h +++ include/llvm/ObjectYAML/WasmYAML.h @@ -138,7 +138,9 @@ union { uint32_t ElementIndex; wasm::WasmDataReference DataRef; + SectionType SectionType; }; + StringRef SectionName; // present when SectionType is a custom section }; struct InitFunction { 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; }; @@ -150,6 +152,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; @@ -169,10 +173,10 @@ struct WasmCustomSection { StringRef Name; - const SmallVectorImpl &Contents; + MCSectionWasm *Section; - WasmCustomSection(StringRef Name, const SmallVectorImpl &Contents) - : Name(Name), Contents(Contents) {} + WasmCustomSection(StringRef Name, MCSectionWasm *Section) + : Name(Name), Section(Section) {} }; #if !defined(NDEBUG) @@ -192,6 +196,9 @@ // Relocations for fixing up references in the data section. std::vector DataRelocations; + // Relocations for fixing up references in the custom sections. + StringMap> 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; @@ -204,6 +211,10 @@ DenseMap WasmIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. DenseMap DataLocations; + // Maps section symbols to the section. + DenseMap CustomSectionSymbols; + // Maps section symbols to the output section offset. + DenseMap CustomSectionOutputOffsets; DenseMap FunctionTypeIndices; @@ -236,15 +247,19 @@ 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(); DataSegments.clear(); + CustomSectionSymbols.clear(); + CustomSectionOutputOffsets.clear(); MCObjectWriter::reset(); NumFunctionImports = 0; NumGlobalImports = 0; @@ -282,11 +297,16 @@ void writeDataSection(); void writeCodeRelocSection(); void writeDataRelocSection(); + void writeCustomRelocSections(); void writeLinkingMetaDataSection( ArrayRef SymbolInfos, ArrayRef> InitFuncs, const std::map> &Comdats); - void writeUserCustomSections(ArrayRef CustomSections); + void writeCustomSections(const MCAssembler &Asm, const MCAsmLayout &Layout, + ArrayRef CustomSections); + void + updateCustomSectionRelocations(const SmallVector &Functions, + const MCAsmLayout &Layout); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, @@ -318,20 +338,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(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"); @@ -372,8 +395,9 @@ 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()) { @@ -444,21 +468,30 @@ 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_")); + const auto &FixupSectionName = FixupSection.getSectionName().str(); + CustomSectionsRelocations[FixupSectionName].push_back(Rec); + } else { llvm_unreachable("unexpected section type"); + } } // Write X as an (unsigned) LEB value at offset Offset in Stream, padded @@ -521,6 +554,15 @@ 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 = *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: { @@ -612,6 +654,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: @@ -871,6 +915,25 @@ endSection(Section); } +void WasmObjectWriter::writeCustomRelocSections() { + for (const auto &P : CustomSectionsRelocations) { + auto CustomSectionName = P.first(); + auto CustomSectionRelocations = P.second; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_CUSTOM, + ("reloc." + CustomSectionName).str().c_str()); + + encodeULEB128(wasm::WASM_SEC_CUSTOM, getStream()); + writeString(CustomSectionName); + encodeULEB128(CustomSectionRelocations.size(), getStream()); + + writeRelocations(CustomSectionRelocations); + + endSection(Section); + } +} + void WasmObjectWriter::writeLinkingMetaDataSection( ArrayRef SymbolInfos, ArrayRef> InitFuncs, @@ -900,6 +963,11 @@ encodeULEB128(Sym.DataRef.Size, getStream()); } break; + case wasm::WASM_SYMBOL_TYPE_SECTION: + encodeULEB128(Sym.SectionCode, getStream()); + if (Sym.SectionCode == wasm::WASM_SEC_CUSTOM) + writeString(Sym.SectionName); + break; default: llvm_unreachable("unexpected kind"); } @@ -946,17 +1014,70 @@ endSection(Section); } -void WasmObjectWriter::writeUserCustomSections( +void WasmObjectWriter::writeCustomSections( + const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef CustomSections) { - for (const auto &CustomSection : CustomSections) { + for (auto &CustomSection : CustomSections) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, CustomSection.Name.str().c_str()); - writeBytes(CustomSection.Contents); + + auto *Sec = CustomSection.Section; + Sec->setSectionOffset(getStream().tell() - Section.ContentsOffset); + Asm.writeSectionData(Sec, Layout); + + CustomSectionOutputOffsets[Sec] = Section.ContentsOffset; + endSection(Section); } } +void WasmObjectWriter::updateCustomSectionRelocations( + const SmallVector &Functions, const MCAsmLayout &Layout) { + std::map SectionSymbols; + for (const auto &P : CustomSectionSymbols) + SectionSymbols[P.second] = P.first; + std::map FuncSymbols; + for (const auto &FuncInfo : Functions) + FuncSymbols[&FuncInfo.Sym->getSection()] = FuncInfo.Sym; + StringMap CustomSectionsByName; + for (auto &P : CustomSectionSymbols) + CustomSectionsByName[P.second->getSectionName()] = P.second; + + // 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 &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.Addend += Layout.getSymbolOffset(*RelEntry.Symbol); + RelEntry.Symbol = FuncSymbols[&Section]; + break; + } + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + assert(RelEntry.hasAddend()); + auto &Section = + static_cast(RelEntry.Symbol->getSection()); + RelEntry.Addend += Layout.getSymbolOffset(*RelEntry.Symbol); + RelEntry.Symbol = SectionSymbols[&Section]; + break; + } + default: + break; + } + } + + // Apply fixups. + const auto &Section = CustomSectionsByName.find(P.first())->second; + applyRelocations(P.second, CustomSectionOutputOffsets[Section]); + } +} + uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm& Symbol) { assert(Symbol.isFunction()); assert(TypeIndices.count(&Symbol)); @@ -1063,8 +1184,7 @@ for (MCSection &Sec : Asm) { auto &Section = static_cast(Sec); - if (cast(Sec).getSectionName().startswith( - ".custom_section.")) { + if (Section.getSectionName().startswith(".custom_section.")) { if (Section.getFragmentList().empty()) continue; if (Section.getFragmentList().size() != 1) @@ -1077,8 +1197,7 @@ 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)); + CustomSections.emplace_back(UserName, &Section); continue; } @@ -1108,6 +1227,31 @@ } } + // Create symbols for debug/custom sections. + for (MCSection &Sec : Asm) { + auto &DebugSection = static_cast(Sec); + StringRef SectionName = DebugSection.getSectionName(); + + // TODO: Add support for non-debug metadata sections? + if (!Sec.getKind().isMetadata() || !SectionName.startswith(".debug_")) + continue; + + CustomSections.emplace_back(SectionName, &DebugSection); + + MCSymbolWasm *SectionSym = + cast(Ctx.getOrCreateSymbol(SectionName)); + CustomSectionSymbols[SectionSym] = &DebugSection; + + wasm::WasmSymbolInfo Info; + Info.Name = SectionSym->getName(); + Info.Kind = wasm::WASM_SYMBOL_TYPE_SECTION; + Info.Flags = 0; + Info.SectionCode = wasm::WASM_SEC_CUSTOM; + Info.SectionName = 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, @@ -1351,13 +1495,14 @@ writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); writeDataSection(); - writeUserCustomSections(CustomSections); + writeCustomSections(Asm, Layout, CustomSections); + updateCustomSectionRelocations(Functions, Layout); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); writeCodeRelocSection(); writeDataRelocSection(); + writeCustomRelocSections(); // TODO: Translate the .comment section to the output. - // TODO: Translate debug sections to the output. } std::unique_ptr Index: lib/Object/WasmObjectFile.cpp =================================================================== --- lib/Object/WasmObjectFile.cpp +++ lib/Object/WasmObjectFile.cpp @@ -465,6 +465,22 @@ } break; + case wasm::WASM_SYMBOL_TYPE_SECTION: { + Info.SectionCode = readVaruint32(Ptr); + if (Info.SectionCode != wasm::WASM_SEC_CUSTOM) + return make_error("invalid section symbol target", + object_error::parse_failed); + Info.SectionName = readString(Ptr); + if (!findCustomSectionByName(Info.SectionName)) + return make_error( + "referred symbol section " + Info.SectionName + " is missing", + object_error::parse_failed); + + // Use somewhat unique section name as symbol name. + Info.Name = Info.SectionName; + break; + } + default: return make_error("Invalid symbol type", object_error::parse_failed); @@ -596,6 +612,18 @@ object_error::parse_failed); Reloc.Addend = readVarint32(Ptr); break; + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + if (!isValidFunctionSymbol(Reloc.Index)) + return make_error("Bad relocation function index", + object_error::parse_failed); + Reloc.Addend = readVarint32(Ptr); + break; + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + if (!isValidSectionSymbol(Reloc.Index)) + return make_error("Bad relocation section index", + object_error::parse_failed); + Reloc.Addend = readVarint32(Ptr); + break; default: return make_error("Bad relocation type: " + Twine(Reloc.Type), @@ -607,7 +635,9 @@ // to check that. uint64_t Size = 5; if (Reloc.Type == wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 || - Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32) + Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32 || + Reloc.Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32 || + Reloc.Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32) Size = 4; if (Reloc.Offset + Size > EndOffset) return make_error("Bad relocation offset", @@ -834,6 +864,10 @@ return Index < Symbols.size() && Symbols[Index].isTypeData(); } +bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeSection(); +} + wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) { assert(isDefinedFunctionIndex(Index)); return Functions[Index - NumImportedFunctions]; @@ -1014,6 +1048,8 @@ assert(Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST); return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset; } + case wasm::WASM_SYMBOL_TYPE_SECTION: + return 0; // TODO(yury): section offset from top of the object file? } llvm_unreachable("invalid symbol type"); } @@ -1043,6 +1079,8 @@ return SymbolRef::ST_Other; case wasm::WASM_SYMBOL_TYPE_DATA: return SymbolRef::ST_Data; + case wasm::WASM_SYMBOL_TYPE_SECTION: + return SymbolRef::ST_Debug; } llvm_unreachable("Unknown WasmSymbol::SymbolType"); @@ -1066,6 +1104,18 @@ case wasm::WASM_SYMBOL_TYPE_DATA: Ref.d.a = DataSection; break; + case wasm::WASM_SYMBOL_TYPE_SECTION: { + assert(Sym.Info.SectionCode == wasm::WASM_SEC_CUSTOM); + // Find index of the referred custom section. + auto Section = std::find_if(Sections.begin(), Sections.end(), + [&](const WasmSection &Sec) -> bool { + return Sec.Type == wasm::WASM_SEC_CUSTOM && + Sec.Name == Sym.Info.SectionName; + }); + assert(Section != Sections.end()); + Ref.d.a = std::distance(Sections.begin(), Section); + break; + } default: llvm_unreachable("Unknown WasmSymbol::SymbolType"); } @@ -1170,10 +1220,12 @@ return Rel.Offset; } -symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Rel) const { - llvm_unreachable("not yet implemented"); - SymbolRef Ref; - return symbol_iterator(Ref); +symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const { + const wasm::WasmRelocation &Rel = getWasmRelocation(Ref); + DataRefImpl Sym; + Sym.d.a = Rel.Index; + Sym.d.b = 0; + return symbol_iterator(SymbolRef(Sym, this)); } uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const { Index: lib/ObjectYAML/WasmYAML.cpp =================================================================== --- lib/ObjectYAML/WasmYAML.cpp +++ lib/ObjectYAML/WasmYAML.cpp @@ -404,6 +404,10 @@ IO.mapOptional("Offset", Info.DataRef.Offset, 0u); IO.mapRequired("Size", Info.DataRef.Size); } + } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION) { + IO.mapRequired("SectionType", Info.SectionType); + if (Info.SectionType == wasm::WASM_SEC_CUSTOM) + IO.mapRequired("SectionName", Info.SectionName); } else { llvm_unreachable("unsupported symbol kind"); } @@ -438,6 +442,7 @@ ECase(FUNCTION); ECase(DATA); ECase(GLOBAL); + ECase(SECTION); #undef ECase } Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -20,9 +20,10 @@ #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSymbolWasm.h" -#include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/MC/MCValue.h" +#include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -61,6 +62,25 @@ return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX; } +static const MCSection *GetFixupSection(const MCExpr *Expr) { + if (auto SyExp = dyn_cast(Expr)) { + if (SyExp->getSymbol().isInSection()) + return &SyExp->getSymbol().getSection(); + return nullptr; + } + + 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 +106,13 @@ 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"); Index: test/MC/WebAssembly/debug-info.ll =================================================================== --- test/MC/WebAssembly/debug-info.ll +++ test/MC/WebAssembly/debug-info.ll @@ -1,9 +1,169 @@ -; RUN: llc -filetype=obj %s -o - | llvm-readobj -r -s -expand-relocs +; RUN: llc -filetype=obj %s -o - | llvm-readobj -r -s | FileCheck %s + +; CHECK: Format: WASM +; CHECK-NEXT:Arch: wasm32 +; CHECK-NEXT:AddressSize: 32bit +; CHECK-NEXT:Sections [ +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: TYPE (0x1) +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: Offset: 8 +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: IMPORT (0x2) +; CHECK-NEXT: Size: 58 +; CHECK-NEXT: Offset: 18 +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: FUNCTION (0x3) +; CHECK-NEXT: Size: 2 +; CHECK-NEXT: Offset: 82 +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: ELEM (0x9) +; CHECK-NEXT: Size: 7 +; CHECK-NEXT: Offset: 90 +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CODE (0xA) +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: Offset: 103 +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: DATA (0xB) +; CHECK-NEXT: Size: 19 +; CHECK-NEXT: Offset: 113 +; CHECK-NEXT: Segments [ +; CHECK-NEXT: Segment { +; CHECK-NEXT: Name: .data.foo +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: Offset: 0 +; CHECK-NEXT: } +; CHECK-NEXT: Segment { +; CHECK-NEXT: Name: .data.ptr2 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: Offset: 4 +; CHECK-NEXT: } +; CHECK-NEXT: ] +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 132 +; CHECK-NEXT: Offset: 138 +; CHECK-NEXT: Name: .debug_str +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 98 +; CHECK-NEXT: Offset: 276 +; CHECK-NEXT: Name: .debug_abbrev +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 118 +; CHECK-NEXT: Offset: 380 +; CHECK-NEXT: Name: .debug_info +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 14 +; CHECK-NEXT: Offset: 504 +; CHECK-NEXT: Name: .debug_ranges +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 16 +; CHECK-NEXT: Offset: 524 +; CHECK-NEXT: Name: .debug_macinfo +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 58 +; CHECK-NEXT: Offset: 546 +; CHECK-NEXT: Name: .debug_pubnames +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 42 +; CHECK-NEXT: Offset: 610 +; CHECK-NEXT: Name: .debug_pubtypes +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 69 +; CHECK-NEXT: Offset: 658 +; CHECK-NEXT: Name: .debug_line +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 217 +; CHECK-NEXT: Offset: 733 +; CHECK-NEXT: Name: linking +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 20 +; CHECK-NEXT: Offset: 956 +; CHECK-NEXT: Name: reloc.DATA +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 88 +; CHECK-NEXT: Offset: 982 +; CHECK-NEXT: Name: reloc..debug_info +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 44 +; CHECK-NEXT: Offset: 1076 +; CHECK-NEXT: Name: reloc..debug_pubtypes +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 36 +; CHECK-NEXT: Offset: 1126 +; CHECK-NEXT: Name: reloc..debug_line +; CHECK-NEXT: } +; CHECK-NEXT: Section { +; CHECK-NEXT: Type: CUSTOM (0x0) +; CHECK-NEXT: Size: 44 +; CHECK-NEXT: Offset: 1168 +; CHECK-NEXT: Name: reloc..debug_pubnames +; CHECK-NEXT: } +; CHECK-NEXT:] +; CHECK-NEXT:Relocations [ +; CHECK-NEXT: Section (6) DATA { +; CHECK-NEXT: 0x6 R_WEBASSEMBLY_MEMORY_ADDR_I32[10] 0 +; CHECK-NEXT: 0xF R_WEBASSEMBLY_TABLE_INDEX_I32[8] +; CHECK-NEXT: } +; CHECK-NEXT: Section (9) .debug_info { +; CHECK-NEXT: 0x6 R_WEBASSEMBLY_SECTION_OFFSET_I32[1] 0 +; CHECK-NEXT: 0xC R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 0 +; CHECK-NEXT: 0x12 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 55 +; CHECK-NEXT: 0x16 R_WEBASSEMBLY_SECTION_OFFSET_I32[7] 0 +; CHECK-NEXT: 0x1A R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 62 +; CHECK-NEXT: 0x1E R_WEBASSEMBLY_FUNCTION_OFFSET_I32[8] 0 +; CHECK-NEXT: 0x27 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 105 +; CHECK-NEXT: 0x33 R_WEBASSEMBLY_MEMORY_ADDR_I32[9] 0 +; CHECK-NEXT: 0x3D R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 109 +; CHECK-NEXT: 0x44 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 113 +; CHECK-NEXT: 0x50 R_WEBASSEMBLY_MEMORY_ADDR_I32[11] 0 +; CHECK-NEXT: 0x5B R_WEBASSEMBLY_FUNCTION_OFFSET_I32[8] 0 +; CHECK-NEXT: 0x63 R_WEBASSEMBLY_SECTION_OFFSET_I32[0] 118 +; CHECK-NEXT: } +; CHECK-NEXT: Section (12) .debug_pubnames { +; CHECK-NEXT: 0x6 R_WEBASSEMBLY_SECTION_OFFSET_I32[2] 0 +; CHECK-NEXT: } +; CHECK-NEXT: Section (13) .debug_pubtypes { +; CHECK-NEXT: 0x6 R_WEBASSEMBLY_SECTION_OFFSET_I32[2] 0 +; CHECK-NEXT: } +; CHECK-NEXT: Section (14) .debug_line { +; CHECK-NEXT: 0x2B R_WEBASSEMBLY_FUNCTION_OFFSET_I32[8] 0 +; CHECK-NEXT: } +; CHECK-NEXT:] target triple = "wasm32-unknown-unknown-wasm" -; Debug information is currently not supported. This test simply verifies that -; a valid object generated. source_filename = "test.c" @myextern = external global i32, align 4 Index: test/MC/WebAssembly/dwarfdump.ll =================================================================== --- /dev/null +++ test/MC/WebAssembly/dwarfdump.ll @@ -0,0 +1,95 @@ +; RUN: llc -filetype=obj %s -o - | llvm-dwarfdump - | FileCheck %s + +; CHECK: .debug_info contents: +; CHECK-NEXT: 0x00000000: Compile Unit: length = 0x00000066 version = 0x0004 abbr_offset = 0x0000 addr_size = 0x04 (next unit at 0x0000006a) + +; CHECK: 0x0000000b: DW_TAG_compile_unit +; CHECK-NEXT: DW_AT_producer ("clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)") +; CHECK-NEXT: DW_AT_language (DW_LANG_C99) +; CHECK-NEXT: DW_AT_name ("test.c") +; CHECK-NEXT: DW_AT_stmt_list (0x00000000) +; CHECK-NEXT: DW_AT_comp_dir ("/usr/local/google/home/sbc/dev/wasm/simple") +; CHECK-NEXT: DW_AT_GNU_pubnames (true) +; CHECK-NEXT: DW_AT_low_pc (0x0000000000000002) +; CHECK-NEXT: DW_AT_high_pc (0x0000000000000004) + +; CHECK: 0x00000026: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("foo") +; CHECK-NEXT: DW_AT_type (0x00000037 "int*") +; CHECK-NEXT: DW_AT_external (true) +; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple/test.c") +; CHECK-NEXT: DW_AT_decl_line (4) +; CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0) + +; CHECK: 0x00000037: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x0000003c "int") + +; CHECK: 0x0000003c: DW_TAG_base_type +; CHECK-NEXT: DW_AT_name ("int") +; CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +; CHECK-NEXT: DW_AT_byte_size (0x04) + +; CHECK: 0x00000043: DW_TAG_variable +; CHECK-NEXT: DW_AT_name ("ptr2") +; CHECK-NEXT: DW_AT_type (0x00000054 "subroutine *") +; CHECK-NEXT: DW_AT_external (true) +; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple/test.c") +; CHECK-NEXT: DW_AT_decl_line (5) +; CHECK-NEXT: DW_AT_location (DW_OP_addr 0x4) + +; CHECK: 0x00000054: DW_TAG_pointer_type +; CHECK-NEXT: DW_AT_type (0x00000059 "subroutine ") + +; CHECK: 0x00000059: DW_TAG_subroutine_type +; CHECK-NEXT: DW_AT_prototyped (true) + +; CHECK: 0x0000005a: DW_TAG_subprogram +; CHECK-NEXT: DW_AT_low_pc (0x0000000000000002) +; CHECK-NEXT: DW_AT_high_pc (0x0000000000000004) +; CHECK-NEXT: DW_AT_name ("f2") +; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple/test.c") +; CHECK-NEXT: DW_AT_decl_line (2) +; CHECK-NEXT: DW_AT_prototyped (true) +; CHECK-NEXT: DW_AT_external (true) + +; CHECK: 0x00000069: NULL + +target triple = "wasm32-unknown-unknown-wasm" + +source_filename = "test.c" + +@myextern = external global i32, align 4 +@foo = hidden global i32* @myextern, align 4, !dbg !0 +@ptr2 = hidden global void ()* @f2, align 4, !dbg !6 + +; Function Attrs: noinline nounwind optnone +define hidden void @f2() #0 !dbg !17 { +entry: + ret void, !dbg !18 +} + +attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!13, !14, !15} +!llvm.ident = !{!16} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, line: 4, type: !11, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "test.c", directory: "/usr/local/google/home/sbc/dev/wasm/simple") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "ptr2", scope: !2, file: !3, line: 5, type: !8, isLocal: false, isDefinition: true) +!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 32) +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 32) +!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!13 = !{i32 2, !"Dwarf Version", i32 4} +!14 = !{i32 2, !"Debug Info Version", i32 3} +!15 = !{i32 1, !"wchar_size", i32 4} +!16 = !{!"clang version 6.0.0 (trunk 315924) (llvm/trunk 315960)"} +!17 = distinct !DISubprogram(name: "f2", scope: !3, file: !3, line: 2, type: !9, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !2, variables: !4) +!18 = !DILocation(line: 2, column: 16, scope: !17) Index: tools/llvm-readobj/WasmDumper.cpp =================================================================== --- tools/llvm-readobj/WasmDumper.cpp +++ tools/llvm-readobj/WasmDumper.cpp @@ -84,6 +84,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: HasAddend = true; break; default: Index: tools/obj2yaml/wasm2yaml.cpp =================================================================== --- tools/obj2yaml/wasm2yaml.cpp +++ tools/obj2yaml/wasm2yaml.cpp @@ -102,6 +102,10 @@ case wasm::WASM_SYMBOL_TYPE_GLOBAL: Info.ElementIndex = Symbol.ElementIndex; break; + case wasm::WASM_SYMBOL_TYPE_SECTION: + Info.SectionType = Symbol.SectionCode; + Info.SectionName = Symbol.SectionName; + break; } LinkingSec->SymbolTable.emplace_back(Info); } Index: tools/yaml2obj/yaml2wasm.cpp =================================================================== --- tools/yaml2obj/yaml2wasm.cpp +++ tools/yaml2obj/yaml2wasm.cpp @@ -163,6 +163,11 @@ encodeULEB128(Info.DataRef.Size, SubSection.GetStream()); } break; + case wasm::WASM_SYMBOL_TYPE_SECTION: + encodeULEB128(Info.SectionType, SubSection.GetStream()); + if (Info.SectionType == wasm::WASM_SEC_CUSTOM) + writeStringRef(Info.SectionName, SubSection.GetStream()); + break; default: llvm_unreachable("unexpected kind"); } @@ -422,21 +427,31 @@ int WasmWriter::writeRelocSection(raw_ostream &OS, WasmYAML::Section &Sec) { - StringRef Name; switch (Sec.Type) { case wasm::WASM_SEC_CODE: - Name = "reloc.CODE"; + writeStringRef("reloc.CODE", OS); break; case wasm::WASM_SEC_DATA: - Name = "reloc.DATA"; + writeStringRef("reloc.DATA", OS); + break; + case wasm::WASM_SEC_CUSTOM: { + auto CustomSection = dyn_cast(&Sec); + if (!CustomSection->Name.startswith(".debug_")) { + llvm_unreachable("not yet implemented (only for debug sections)"); + return 1; + } + + writeStringRef(("reloc." + CustomSection->Name).str(), OS); break; + } default: llvm_unreachable("not yet implemented"); return 1; } - writeStringRef(Name, OS); writeUint8(OS, Sec.Type); + if (Sec.Type == wasm::WASM_SEC_CUSTOM) + writeStringRef(dyn_cast(&Sec)->Name, OS); encodeULEB128(Sec.Relocations.size(), OS); for (auto Reloc: Sec.Relocations) { @@ -447,6 +462,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: encodeULEB128(Reloc.Addend, OS); } }