Index: test/wasm/Inputs/debuginfo1.ll =================================================================== --- /dev/null +++ test/wasm/Inputs/debuginfo1.ll @@ -0,0 +1,68 @@ +; ModuleID = 'hi.c' +source_filename = "hi.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +; // hi.c: +; extern void foo(int); +; +; int test(int t) { +; return t * t; +; } +; +; int _start() { +; foo(test(10)); +; return 0; +; } + +; Function Attrs: nounwind readnone +define hidden i32 @test(i32 %t) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %t, metadata !12, metadata !DIExpression()), !dbg !13 + %mul = mul nsw i32 %t, %t, !dbg !14 + ret i32 %mul, !dbg !15 +} + +; Function Attrs: nounwind +define hidden i32 @_start() local_unnamed_addr #1 !dbg !16 { +entry: + tail call void @foo(i32 100) #4, !dbg !19 + ret i32 0, !dbg !20 +} + +declare void @foo(i32) local_unnamed_addr #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind readnone "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" } +attributes #1 = { nounwind "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" } +attributes #2 = { "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-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" } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "hi.c", directory: "/Users/yury/llvmwasm") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 7.0.0 (trunk 331321)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "t", arg: 1, scope: !7, file: !1, line: 3, type: !10) +!13 = !DILocation(line: 3, column: 14, scope: !7) +!14 = !DILocation(line: 4, column: 12, scope: !7) +!15 = !DILocation(line: 4, column: 3, scope: !7) +!16 = distinct !DISubprogram(name: "_start", scope: !1, file: !1, line: 7, type: !17, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, variables: !2) +!17 = !DISubroutineType(types: !18) +!18 = !{!10} +!19 = !DILocation(line: 8, column: 3, scope: !16) +!20 = !DILocation(line: 9, column: 3, scope: !16) Index: test/wasm/Inputs/debuginfo2.ll =================================================================== --- /dev/null +++ test/wasm/Inputs/debuginfo2.ll @@ -0,0 +1,64 @@ +; ModuleID = 'hi_foo.c' +source_filename = "hi_foo.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +; // hi_foo.c: +; int y[2] = {23, 41}; +; +; void foo(int p) { +; y[p & 1]++; +; } + +@y = hidden local_unnamed_addr global [2 x i32] [i32 23, i32 41], align 4, !dbg !0 + +; Function Attrs: nounwind +define hidden void @foo(i32 %p) local_unnamed_addr #0 !dbg !14 { +entry: + call void @llvm.dbg.value(metadata i32 %p, metadata !18, metadata !DIExpression()), !dbg !19 + %and = and i32 %p, 1, !dbg !20 + %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @y, i32 0, i32 %and, !dbg !21 + %0 = load i32, i32* %arrayidx, align 4, !dbg !22, !tbaa !23 + %inc = add nsw i32 %0, 1, !dbg !22 + store i32 %inc, i32* %arrayidx, align 4, !dbg !22, !tbaa !23 + ret void, !dbg !27 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind "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" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!10, !11, !12} +!llvm.ident = !{!13} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "hi_foo.c", directory: "/Users/yury/llvmwasm") +!4 = !{} +!5 = !{!0} +!6 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 64, elements: !8) +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{!9} +!9 = !DISubrange(count: 2) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{!"clang version 7.0.0 (trunk 331321)"} +!14 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !15, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, variables: !17) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !7} +!17 = !{!18} +!18 = !DILocalVariable(name: "p", arg: 1, scope: !14, file: !3, line: 3, type: !7) +!19 = !DILocation(line: 3, column: 14, scope: !14) +!20 = !DILocation(line: 4, column: 7, scope: !14) +!21 = !DILocation(line: 4, column: 3, scope: !14) +!22 = !DILocation(line: 4, column: 11, scope: !14) +!23 = !{!24, !24, i64 0} +!24 = !{!"int", !25, i64 0} +!25 = !{!"omnipotent char", !26, i64 0} +!26 = !{!"Simple C/C++ TBAA"} +!27 = !DILocation(line: 5, column: 1, scope: !14) Index: test/wasm/debuginfo.test =================================================================== --- /dev/null +++ test/wasm/debuginfo.test @@ -0,0 +1,73 @@ +RUN: llc -filetype=obj %p/Inputs/debuginfo1.ll -o %t.debuginfo1.o +RUN: llc -filetype=obj %p/Inputs/debuginfo2.ll -o %t.debuginfo2.o +RUN: wasm-ld -r -o %t.wasm %t.debuginfo1.o %t.debuginfo2.o +RUN: llvm-dwarfdump %t.wasm | FileCheck %s + +CHECK: file format WASM + +CHECK: .debug_info contents: +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk 331321)") +CHECK-NEXT: DW_AT_language (DW_LANG_C99) +CHECK-NEXT: DW_AT_name ("hi.c") + +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_low_pc +CHECK-NEXT: DW_AT_high_pc +CHECK-NEXT: DW_AT_name ("test") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi.c") +CHECK-NEXT: DW_AT_decl_line (3) +CHECK-NEXT: DW_AT_prototyped (true) + +CHECK: DW_TAG_formal_parameter +CHECK-NEXT: DW_AT_name ("t") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi.c") +CHECK-NEXT: DW_AT_decl_line (3) + +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_low_pc +CHECK-NEXT: DW_AT_high_pc +CHECK-NEXT: DW_AT_name ("_start") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi.c") +CHECK-NEXT: DW_AT_decl_line (7) + +CHECK: 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: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk 331321)") +CHECK-NEXT: DW_AT_language (DW_LANG_C99) +CHECK-NEXT: DW_AT_name ("hi_foo.c") + +CHECK: DW_TAG_variable +CHECK-NEXT: DW_AT_name ("y") +CHECK-NEXT: "int[]" + +CHECK: DW_TAG_array_type + +CHECK: DW_TAG_subrange_type + +CHECK: 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: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("__ARRAY_SIZE_TYPE__") +CHECK-NEXT: DW_AT_byte_size (0x08) +CHECK-NEXT: DW_AT_encoding (DW_ATE_unsigned) + +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_low_pc +CHECK-NEXT: DW_AT_high_pc +CHECK-NEXT: DW_AT_name ("foo") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi_foo.c") +CHECK-NEXT: DW_AT_decl_line (3) + +CHECK: DW_TAG_formal_parameter +CHECK-NEXT: DW_AT_name ("p") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm/hi_foo.c") +CHECK-NEXT: DW_AT_decl_line (3) + Index: wasm/InputChunks.h =================================================================== --- wasm/InputChunks.h +++ wasm/InputChunks.h @@ -130,6 +130,8 @@ StringRef getName() const override { return Function->SymbolName; } StringRef getDebugName() const override { return Function->DebugName; } uint32_t getComdat() const override { return Function->Comdat; } + const ArrayRef getFunctionBody() const { return Function->Body; } + uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); } uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); } bool hasFunctionIndex() const { return FunctionIndex.hasValue(); } void setFunctionIndex(uint32_t Index); Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -89,6 +89,8 @@ break; case R_WEBASSEMBLY_TABLE_INDEX_I32: case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case R_WEBASSEMBLY_SECTION_OFFSET_I32: ExistingValue = static_cast(read32le(Loc)); write32le(Loc, Value); break; @@ -124,7 +126,9 @@ case R_WEBASSEMBLY_MEMORY_ADDR_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_I32: - writeSleb128(OS, Rel.Addend, "reloc addend"); + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend"); break; } } Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -95,6 +95,7 @@ uint32_t calcNewIndex(const WasmRelocation &Reloc) const; uint32_t calcNewValue(const WasmRelocation &Reloc) const; + uint32_t calcNewAddend(const WasmRelocation &Reloc) const; uint32_t calcExpectedValue(const WasmRelocation &Reloc) const; const WasmSection *CodeSection = nullptr; @@ -110,12 +111,14 @@ std::vector Functions; std::vector Globals; std::vector CustomSections; + llvm::DenseMap CustomSectionsByIndex; ArrayRef getSymbols() const { return Symbols; } Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; } FunctionSymbol *getFunctionSymbol(uint32_t Index) const; DataSymbol *getDataSymbol(uint32_t Index) const; GlobalSymbol *getGlobalSymbol(uint32_t Index) const; + SectionSymbol *getSectionSymbol(uint32_t Index) const; private: Symbol *createDefined(const WasmSymbol &Sym); Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -16,6 +16,7 @@ #include "lld/Common/Memory.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Wasm.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "lld" @@ -42,6 +43,12 @@ return MBRef; } +static size_t getFunctionCodeOffset(ArrayRef FunctionBody) { + unsigned Count; + llvm::decodeULEB128(FunctionBody.data(), &Count); + return Count; +} + void ObjFile::dumpInfo() const { log("info for: " + getName() + "\n Symbols : " + Twine(Symbols.size()) + @@ -60,6 +67,22 @@ return Symbols[Reloc.Index]->getOutputSymbolIndex(); } +// Relocations can contain addend for combined sections. This function takes a +// relocation and returns updated addend by offset in the output section. +uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const { + switch (Reloc.Type) { + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + return Reloc.Addend; + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend; + default: + llvm_unreachable("unexpected relocation type"); + } +} + // Calculate the value we expect to find at the relocation location. // This is used as a sanity check before applying a relocation to a given // location. It is useful for catching bugs in the compiler and linker. @@ -80,6 +103,16 @@ return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset + Reloc.Addend; } + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + if (auto *Sym = dyn_cast(getFunctionSymbol(Reloc.Index))) { + size_t FunctionCodeOffset = + getFunctionCodeOffset(Sym->Function->getFunctionBody()); + return Sym->Function->getFunctionInputOffset() + FunctionCodeOffset + + Reloc.Addend; + } + return 0; + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + return Reloc.Addend; case R_WEBASSEMBLY_TYPE_INDEX_LEB: return Reloc.Index; case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: @@ -110,6 +143,15 @@ return getFunctionSymbol(Reloc.Index)->getFunctionIndex(); case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: return getGlobalSymbol(Reloc.Index)->getGlobalIndex(); + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + if (auto *Sym = dyn_cast(getFunctionSymbol(Reloc.Index))) { + size_t FunctionCodeOffset = + getFunctionCodeOffset(Sym->Function->getFunctionBody()); + return Sym->Function->OutputOffset + FunctionCodeOffset + Reloc.Addend; + } + return 0; + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend; default: llvm_unreachable("unknown relocation type"); } @@ -147,14 +189,19 @@ // Find the code and data sections. Wasm objects can have at most one code // and one data section. + uint32_t SectionIndex = 0; for (const SectionRef &Sec : WasmObj->sections()) { const WasmSection &Section = WasmObj->getWasmSection(Sec); - if (Section.Type == WASM_SEC_CODE) + if (Section.Type == WASM_SEC_CODE) { CodeSection = &Section; - else if (Section.Type == WASM_SEC_DATA) + } else if (Section.Type == WASM_SEC_DATA) { DataSection = &Section; - else if (Section.Type == WASM_SEC_CUSTOM) + } else if (Section.Type == WASM_SEC_CUSTOM) { CustomSections.emplace_back(make(Section, this)); + CustomSections.back()->copyRelocations(Section); + CustomSectionsByIndex[SectionIndex] = CustomSections.back(); + } + SectionIndex++; } TypeMap.resize(getWasmObj()->types().size()); @@ -215,6 +262,10 @@ return cast(Symbols[Index]); } +SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const { + return cast(Symbols[Index]); +} + DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const { return cast(Symbols[Index]); } @@ -253,14 +304,20 @@ return make(Name, Flags, this, Seg, Offset, Size); return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size); } - case WASM_SYMBOL_TYPE_GLOBAL: + case WASM_SYMBOL_TYPE_GLOBAL: { InputGlobal *Global = Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()]; if (Sym.isBindingLocal()) return make(Name, Flags, this, Global); return Symtab->addDefinedGlobal(Name, Flags, this, Global); } - llvm_unreachable("unkown symbol kind"); + case WASM_SYMBOL_TYPE_SECTION: { + InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex]; + assert(Sym.isBindingLocal()); + return make(Name, Flags, Section, this); + } + } + llvm_unreachable("unknown symbol kind"); } Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { @@ -274,8 +331,10 @@ return Symtab->addUndefinedData(Name, Flags, this); case WASM_SYMBOL_TYPE_GLOBAL: return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType); + case WASM_SYMBOL_TYPE_SECTION: + llvm_unreachable("section symbols cannot be undefined"); } - llvm_unreachable("unkown symbol kind"); + llvm_unreachable("unknown symbol kind"); } void ArchiveFile::parse() { Index: wasm/OutputSections.h =================================================================== --- wasm/OutputSections.h +++ wasm/OutputSections.h @@ -127,6 +127,8 @@ return Header.size() + NameData.size() + PayloadSize; } void writeTo(uint8_t *Buf) override; + uint32_t numRelocations() const override; + void writeRelocations(raw_ostream &OS) const override; protected: size_t PayloadSize; Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -224,3 +224,15 @@ parallelForEach(InputSections, [&](const InputSection *Section) { Section->writeTo(Buf); }); } + +uint32_t CustomSection::numRelocations() const { + uint32_t Count = 0; + for (const InputSection *InputSect : InputSections) + Count += InputSect->NumRelocations(); + return Count; +} + +void CustomSection::writeRelocations(raw_ostream &OS) const { + for (const InputSection *S : InputSections) + S->writeRelocations(OS); +} Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -30,6 +30,7 @@ class InputSegment; class InputFunction; class InputGlobal; +class InputSection; #define INVALID_INDEX UINT32_MAX @@ -40,6 +41,7 @@ DefinedFunctionKind, DefinedDataKind, DefinedGlobalKind, + SectionKind, UndefinedFunctionKind, UndefinedDataKind, UndefinedGlobalKind, @@ -50,7 +52,7 @@ bool isDefined() const { return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind || - SymbolKind == DefinedGlobalKind; + SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind; } bool isUndefined() const { @@ -155,6 +157,23 @@ } }; +class SectionSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { return S->kind() == SectionKind; } + + SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S, + InputFile *F = nullptr) + : Symbol(Name, SectionKind, Flags, F), Section(S) {} + + const InputSection *Section; + + uint32_t getOutputSectionIndex() const; + void setOutputSectionIndex(uint32_t Index); + +protected: + uint32_t OutputSectionIndex = INVALID_INDEX; +}; + class DataSymbol : public Symbol { public: static bool classof(const Symbol *S) { @@ -301,6 +320,7 @@ alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)]; alignas(UndefinedData) char F[sizeof(UndefinedData)]; alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)]; + alignas(SectionSymbol) char I[sizeof(SectionSymbol)]; }; template Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -36,6 +36,8 @@ return llvm::wasm::WASM_SYMBOL_TYPE_DATA; if (isa(this)) return llvm::wasm::WASM_SYMBOL_TYPE_GLOBAL; + if (isa(this)) + return llvm::wasm::WASM_SYMBOL_TYPE_SECTION; llvm_unreachable("invalid symbol kind"); } @@ -194,6 +196,19 @@ Global ? &Global->getType() : nullptr), Global(Global) {} +uint32_t SectionSymbol::getOutputSectionIndex() const { + DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n"); + assert(OutputSectionIndex != INVALID_INDEX); + return OutputSectionIndex; +} + +void SectionSymbol::setOutputSectionIndex(uint32_t Index) { + DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index + << "\n"); + assert(Index != INVALID_INDEX); + OutputSectionIndex = Index; +} + void LazySymbol::fetch() { cast(File)->addMember(&ArchiveSymbol); } std::string lld::toString(const wasm::Symbol &Sym) { @@ -219,6 +234,8 @@ return "UndefinedGlobal"; case wasm::Symbol::LazyKind: return "LazyKind"; + case wasm::Symbol::SectionKind: + return "SectionKind"; } llvm_unreachable("invalid symbol kind"); } Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -67,6 +67,7 @@ void assignIndexes(); void calculateImports(); void calculateExports(); + void calculateCustomSections(); void assignSymtab(); void calculateTypes(); void createOutputSegments(); @@ -114,6 +115,7 @@ std::vector InitFunctions; llvm::StringMap> CustomSectionMapping; + llvm::StringMap CustomSectionSymbols; // Elements that are used to construct the final output std::string Header; @@ -299,18 +301,35 @@ } } +void Writer::calculateCustomSections() { + log("calculateCustomSections"); + bool StripDebug = Config->StripDebug || Config->StripAll; + for (ObjFile *File : Symtab->ObjectFiles) { + for (InputSection *Section : File->CustomSections) { + StringRef Name = Section->getName(); + // These custom sections are known the linker and synthesized rather than + // blindly copied + if (Name == "linking" || Name == "name" || Name.startswith("reloc.")) + continue; + // .. or it is a debug section + if (StripDebug && Name.startswith(".debug_")) + continue; + CustomSectionMapping[Name].push_back(Section); + } + } +} + void Writer::createCustomSections() { log("createCustomSections"); - for (ObjFile *File : Symtab->ObjectFiles) - for (InputSection *Section : File->CustomSections) - CustomSectionMapping[Section->getName()].push_back(Section); - for (auto &Pair : CustomSectionMapping) { StringRef Name = Pair.first(); - // These custom sections are known the linker and synthesized rather than - // blindly copied - if (Name == "linking" || Name == "name" || Name.startswith("reloc.")) - continue; + + auto P = CustomSectionSymbols.find(Name); + if (P != CustomSectionSymbols.end()) { + uint32_t SectionIndex = OutputSections.size(); + P->second->setOutputSectionIndex(SectionIndex); + } + DEBUG(dbgs() << "createCustomSection: " << Name << "\n"); OutputSections.push_back(make(Name, Pair.second)); } @@ -375,8 +394,11 @@ Name = "reloc.DATA"; else if (OSec->Type == WASM_SEC_CODE) Name = "reloc.CODE"; + else if (OSec->Type == WASM_SEC_CUSTOM) + Name = Saver.save("reloc." + OSec->Name); else - llvm_unreachable("relocations only supported for code and data"); + llvm_unreachable( + "relocations only supported for code, data, or custom sections"); SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name); raw_ostream &OS = Section->getStream(); @@ -452,8 +474,7 @@ writeUleb128(Sub.OS, G->getGlobalIndex(), "index"); if (Sym->isDefined()) writeStr(Sub.OS, Sym->getName(), "sym name"); - } else { - assert(isa(Sym)); + } else if (auto *D = dyn_cast(Sym)) { writeStr(Sub.OS, Sym->getName(), "sym name"); if (auto *DataSym = dyn_cast(Sym)) { writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index"); @@ -461,6 +482,9 @@ "data offset"); writeUleb128(Sub.OS, DataSym->getSize(), "data size"); } + } else { + auto *S = cast(Sym); + writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index"); } } @@ -751,12 +775,32 @@ if (!Config->Relocatable) return; + StringMap SectionSymbolIndices; + unsigned SymbolIndex = SymtabEntries.size(); for (ObjFile *File : Symtab->ObjectFiles) { DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n"); for (Symbol *Sym : File->getSymbols()) { if (Sym->getFile() != File) continue; + + if (auto *S = dyn_cast(Sym)) { + StringRef Name = S->getName(); + if (CustomSectionMapping.count(Name) == 0) + continue; + + auto SSI = SectionSymbolIndices.find(Name); + if (SSI != SectionSymbolIndices.end()) { + Sym->setOutputSymbolIndex(SSI->second); + continue; + } + + SectionSymbolIndices[Name] = SymbolIndex; + CustomSectionSymbols[Name] = cast(Sym); + + Sym->markLive(); + } + // (Since this is relocatable output, GC is not performed so symbols must // be live.) assert(Sym->isLive()); @@ -855,6 +899,8 @@ HandleRelocs(Chunk); for (InputChunk *Chunk : File->Segments) HandleRelocs(Chunk); + for (auto &P : File->CustomSections) + HandleRelocs(P); } uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size(); @@ -976,6 +1022,8 @@ layoutMemory(); log("-- calculateExports"); calculateExports(); + log("-- calculateCustomSections"); + calculateCustomSections(); log("-- assignSymtab"); assignSymtab();