From 9a72d3e3e456ffa9cfb4e0b2c2e81da78bb15dd3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 8 Dec 2020 21:47:19 -0800 Subject: [PATCH] [WebAssembly] Add support for named data sections in wasm binaries Followup to https://reviews.llvm.org/D91769 which added support for names globals. Differential Revision: https://reviews.llvm.org/D92909 --- lld/test/wasm/call-indirect.ll | 3 +++ lld/test/wasm/data-segment-merging.ll | 8 ++++++-- lld/test/wasm/gc-sections.ll | 6 ++++++ lld/test/wasm/local-symbols.ll | 3 +++ lld/test/wasm/locals-duplicate.test | 10 ++++++++++ lld/test/wasm/map-file.s | 2 +- lld/test/wasm/signature-mismatch.ll | 3 +++ lld/test/wasm/weak-symbols.s | 3 +++ lld/wasm/SyntheticSections.cpp | 23 +++++++++++++++++++++++ lld/wasm/SyntheticSections.h | 8 +++++++- lld/wasm/Writer.cpp | 2 +- llvm/include/llvm/BinaryFormat/Wasm.h | 10 ++++++---- llvm/include/llvm/ObjectYAML/WasmYAML.h | 1 + llvm/lib/Object/WasmObjectFile.cpp | 21 +++++++++++++++------ llvm/lib/ObjectYAML/WasmEmitter.cpp | 13 +++++++++++++ llvm/lib/ObjectYAML/WasmYAML.cpp | 1 + llvm/tools/obj2yaml/wasm2yaml.cpp | 6 ++++-- 17 files changed, 106 insertions(+), 17 deletions(-) diff --git a/lld/test/wasm/call-indirect.ll b/lld/test/wasm/call-indirect.ll index 84a8471..4acc1ed 100644 --- a/lld/test/wasm/call-indirect.ll +++ b/lld/test/wasm/call-indirect.ll @@ -156,4 +156,7 @@ define void @call_ptr(i64 (i64)* %arg) { ; CHECK-NEXT: GlobalNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... diff --git a/lld/test/wasm/data-segment-merging.ll b/lld/test/wasm/data-segment-merging.ll index bc347d1..1dee1cc 100644 --- a/lld/test/wasm/data-segment-merging.ll +++ b/lld/test/wasm/data-segment-merging.ll @@ -31,7 +31,9 @@ ; MERGE-NEXT: GlobalNames: ; MERGE-NEXT: - Index: 0 ; MERGE-NEXT: Name: __stack_pointer -; MERGE-NOT: - Index: +; MERGE-NEXT: DataSegmentNames: +; MERGE-NEXT: - Index: 0 +; MERGE-NEXT: Name: .rodata ; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.o ; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE @@ -71,7 +73,9 @@ ; SEPARATE-NEXT: GlobalNames: ; SEPARATE-NEXT: - Index: 0 ; SEPARATE-NEXT: Name: __stack_pointer -; SEPARATE-NOT: - Index: +; SEPARATE-NEXT: DataSegmentNames: +; SEPARATE-NEXT: - Index: 0 +; SEPARATE-NEXT: Name: .rodata ; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 -o %t.merged.passive.wasm %t.passive.o ; RUN: obj2yaml %t.merged.passive.wasm | FileCheck %s --check-prefix=PASSIVE-MERGE diff --git a/lld/test/wasm/gc-sections.ll b/lld/test/wasm/gc-sections.ll index 8bac2fd..de82986 100644 --- a/lld/test/wasm/gc-sections.ll +++ b/lld/test/wasm/gc-sections.ll @@ -87,6 +87,9 @@ entry: ; CHECK-NEXT: Name: __stack_pointer ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: used_global +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... ; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm \ @@ -162,6 +165,9 @@ entry: ; NO-GC-NEXT: Name: unused_global ; NO-GC-NEXT: - Index: 2 ; NO-GC-NEXT: Name: used_global +; NO-GC-NEXT: DataSegmentNames: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: Name: .data ; NO-GC-NEXT: ... ; RUN: not wasm-ld --gc-sections --relocatable -o %t1.no-gc.wasm %t.o 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR diff --git a/lld/test/wasm/local-symbols.ll b/lld/test/wasm/local-symbols.ll index d0a520a..13c200d 100644 --- a/lld/test/wasm/local-symbols.ll +++ b/lld/test/wasm/local-symbols.ll @@ -97,4 +97,7 @@ entry: ; CHECK-NEXT: GlobalNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... diff --git a/lld/test/wasm/locals-duplicate.test b/lld/test/wasm/locals-duplicate.test index dc6b9c88..07abb74 100644 --- a/lld/test/wasm/locals-duplicate.test +++ b/lld/test/wasm/locals-duplicate.test @@ -212,6 +212,9 @@ ; CHECK-NEXT: GlobalNames: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: DataSegmentNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .data ; CHECK-NEXT: ... @@ -546,4 +549,11 @@ ; RELOC-NEXT: Name: get_func2B ; RELOC-NEXT: - Index: 17 ; RELOC-NEXT: Name: get_func3B +; RELOC-NEXT: DataSegmentNames: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: .data.colliding_global1 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: .data.colliding_global2 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: .data.colliding_global3 ; RELOC-NEXT: ... diff --git a/lld/test/wasm/map-file.s b/lld/test/wasm/map-file.s index e194662..a5bd016 100644 --- a/lld/test/wasm/map-file.s +++ b/lld/test/wasm/map-file.s @@ -40,7 +40,7 @@ somedata: # CHECK-NEXT: 400 5a 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.data.somedata) # CHECK-NEXT: 400 5a 4 somedata # CHECK-NEXT: - 60 12 CUSTOM(.debug_info) -# CHECK-NEXT: - 72 2b CUSTOM(name) +# CHECK-NEXT: - 72 35 CUSTOM(name) # RUN: not wasm-ld %t1.o -o /dev/null -Map=/ 2>&1 \ # RUN: | FileCheck -check-prefix=FAIL %s diff --git a/lld/test/wasm/signature-mismatch.ll b/lld/test/wasm/signature-mismatch.ll index 3e42a74..d5f95b0 100644 --- a/lld/test/wasm/signature-mismatch.ll +++ b/lld/test/wasm/signature-mismatch.ll @@ -55,6 +55,9 @@ declare i32 @ret32(i32, i64, i32) local_unnamed_addr ; YAML-NEXT: GlobalNames: ; YAML-NEXT: - Index: 0 ; YAML-NEXT: Name: __stack_pointer +; YAML-NEXT: DataSegmentNames: +; YAML-NEXT: - Index: 0 +; YAML-NEXT: Name: .data ; YAML-NEXT: ... ; RELOC: Name: linking diff --git a/lld/test/wasm/weak-symbols.s b/lld/test/wasm/weak-symbols.s index 41c8a1a..7557dfb 100644 --- a/lld/test/wasm/weak-symbols.s +++ b/lld/test/wasm/weak-symbols.s @@ -116,4 +116,7 @@ _start: # CHECK-NEXT: GlobalNames: # CHECK-NEXT: - Index: 0 # CHECK-NEXT: Name: __stack_pointer +# CHECK-NEXT: DataSegmentNames: +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: Name: .data # CHECK-NEXT: ... diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp index 3fdcc62..95a4852 100644 --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -562,6 +562,16 @@ unsigned NameSection::numNamedGlobals() const { return numNames; } +unsigned NameSection::numNamedDataSegments() const { + unsigned numNames = 0; + + for (const OutputSegment *s : segments) + if (!s->name.empty()) + ++numNames; + + return numNames; +} + // Create the custom "name" section containing debug symbol names. void NameSection::writeBody() { unsigned count = numNamedFunctions(); @@ -619,6 +629,19 @@ void NameSection::writeBody() { sub.writeTo(bodyOutputStream); } + + count = numNamedDataSegments(); + if (count) { + SubSection sub(WASM_NAMES_DATA_SEGMENT); + writeUleb128(sub.os, count, "name count"); + + for (OutputSegment *s : segments) { + writeUleb128(sub.os, s->index, "global index"); + writeStr(sub.os, s->name, "segment name"); + } + + sub.writeTo(bodyOutputStream); + } } void ProducersSection::addInfo(const WasmProducerInfo &info) { diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h index f9ec7f2..56ba66f 100644 --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -296,7 +296,9 @@ protected: // Create the custom "name" section containing debug symbol names. class NameSection : public SyntheticSection { public: - NameSection() : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name") {} + NameSection(ArrayRef segments) + : SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"), + segments(segments) {} bool isNeeded() const override { return !config->stripDebug && !config->stripAll && numNames() > 0; } @@ -304,6 +306,10 @@ public: unsigned numNames() const { return numNamedGlobals() + numNamedFunctions(); } unsigned numNamedGlobals() const; unsigned numNamedFunctions() const; + unsigned numNamedDataSegments() const; + +protected: + ArrayRef segments; }; class ProducersSection : public SyntheticSection { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 851a6d3..dca6c26 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1210,7 +1210,7 @@ void Writer::createSyntheticSections() { out.elemSec = make(); out.dataCountSec = make(segments); out.linkingSec = make(initFunctions, segments); - out.nameSec = make(); + out.nameSec = make(segments); out.producersSec = make(); out.targetFeaturesSec = make(); } diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 760ddf5..371e9ad 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -202,7 +202,8 @@ struct WasmSymbolInfo { enum class NameType { FUNCTION, - GLOBAL + GLOBAL, + DATA_SEGMENT, }; struct WasmDebugName { @@ -313,9 +314,10 @@ enum : uint8_t { // Kind codes used in the custom "name" section enum : unsigned { - WASM_NAMES_FUNCTION = 0x1, - WASM_NAMES_LOCAL = 0x2, - WASM_NAMES_GLOBAL = 0x7, + WASM_NAMES_FUNCTION = 1, + WASM_NAMES_LOCAL = 2, + WASM_NAMES_GLOBAL = 7, + WASM_NAMES_DATA_SEGMENT = 9, }; // Kind codes used in the custom "linking" section diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h index 28cd560..80f1b40 100644 --- a/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -222,6 +222,7 @@ struct NameSection : CustomSection { std::vector FunctionNames; std::vector GlobalNames; + std::vector DataSegmentNames; }; struct LinkingSection : CustomSection { diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 7c8abcb..c9b13e4 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -357,6 +357,7 @@ Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) { Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { llvm::DenseSet SeenFunctions; llvm::DenseSet SeenGlobals; + llvm::DenseSet SeenSegments; if (FunctionTypes.size() && !SeenCodeSection) { return make_error("Names must come after code section", object_error::parse_failed); @@ -368,11 +369,13 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { const uint8_t *SubSectionEnd = Ctx.Ptr + Size; switch (Type) { case wasm::WASM_NAMES_FUNCTION: - case wasm::WASM_NAMES_GLOBAL: { + case wasm::WASM_NAMES_GLOBAL: + case wasm::WASM_NAMES_DATA_SEGMENT: { uint32_t Count = readVaruint32(Ctx); while (Count--) { uint32_t Index = readVaruint32(Ctx); StringRef Name = readString(Ctx); + wasm::NameType nameType = wasm::NameType::FUNCTION; if (Type == wasm::WASM_NAMES_FUNCTION) { if (!SeenFunctions.insert(Index).second) return make_error( @@ -383,18 +386,24 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { if (isDefinedFunctionIndex(Index)) getDefinedFunction(Index).DebugName = Name; - } else { + } else if (Type == wasm::WASM_NAMES_GLOBAL) { + nameType = wasm::NameType::GLOBAL; if (!SeenGlobals.insert(Index).second) return make_error("Global named more than once", object_error::parse_failed); if (!isValidGlobalIndex(Index) || Name.empty()) return make_error("Invalid name entry", object_error::parse_failed); + } else { + nameType = wasm::NameType::DATA_SEGMENT; + if (!SeenSegments.insert(Index).second) + return make_error( + "Segment named more than once", object_error::parse_failed); + if (Index > DataSegments.size()) + return make_error("Invalid named data segment", + object_error::parse_failed); } - wasm::NameType T = Type == wasm::WASM_NAMES_FUNCTION - ? wasm::NameType::FUNCTION - : wasm::NameType::GLOBAL; - DebugNames.push_back(wasm::WasmDebugName{T, Index, Name}); + DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name}); } break; } diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp index 64498c8..d9f820b 100644 --- a/llvm/lib/ObjectYAML/WasmEmitter.cpp +++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp @@ -283,6 +283,19 @@ void WasmWriter::writeSectionContent(raw_ostream &OS, SubSection.done(); } + if (Section.DataSegmentNames.size()) { + writeUint8(OS, wasm::WASM_NAMES_DATA_SEGMENT); + + SubSectionWriter SubSection(OS); + + encodeULEB128(Section.DataSegmentNames.size(), SubSection.getStream()); + for (const WasmYAML::NameEntry &NameEntry : Section.DataSegmentNames) { + encodeULEB128(NameEntry.Index, SubSection.getStream()); + writeStringRef(NameEntry.Name, SubSection.getStream()); + } + + SubSection.done(); + } } void WasmWriter::writeSectionContent(raw_ostream &OS, diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index a6ad5c3..69c4fd6 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -62,6 +62,7 @@ static void sectionMapping(IO &IO, WasmYAML::NameSection &Section) { IO.mapRequired("Name", Section.Name); IO.mapOptional("FunctionNames", Section.FunctionNames); IO.mapOptional("GlobalNames", Section.GlobalNames); + IO.mapOptional("DataSegmentNames", Section.DataSegmentNames); } static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp index 91855c3..205ec1e 100644 --- a/llvm/tools/obj2yaml/wasm2yaml.cpp +++ b/llvm/tools/obj2yaml/wasm2yaml.cpp @@ -70,9 +70,11 @@ WasmDumper::dumpCustomSection(const WasmSection &WasmSec) { NameEntry.Index = Name.Index; if (Name.Type == llvm::wasm::NameType::FUNCTION) { NameSec->FunctionNames.push_back(NameEntry); - } else { - assert(Name.Type == llvm::wasm::NameType::GLOBAL); + } else if (Name.Type == llvm::wasm::NameType::GLOBAL) { NameSec->GlobalNames.push_back(NameEntry); + } else { + assert(Name.Type == llvm::wasm::NameType::DATA_SEGMENT); + NameSec->DataSegmentNames.push_back(NameEntry); } } CustomSec = std::move(NameSec); -- 2.7.4