diff --git a/lld/test/wasm/Inputs/locals-duplicate1.ll b/lld/test/wasm/Inputs/locals-duplicate1.ll --- a/lld/test/wasm/Inputs/locals-duplicate1.ll +++ b/lld/test/wasm/Inputs/locals-duplicate1.ll @@ -1,11 +1,11 @@ target triple = "wasm32-unknown-unknown" ; Will collide: local (internal linkage) with global (external) linkage -@colliding_global1 = internal default global i32 0, align 4 +@colliding_global1 = internal default global i32 1, align 4 ; Will collide: global with local -@colliding_global2 = default global i32 0, align 4 +@colliding_global2 = default global i32 1, align 4 ; Will collide: local with local -@colliding_global3 = internal default global i32 0, align 4 +@colliding_global3 = internal default global i32 1, align 4 ; Will collide: local with global define internal i32 @colliding_func1() { diff --git a/lld/test/wasm/Inputs/locals-duplicate2.ll b/lld/test/wasm/Inputs/locals-duplicate2.ll --- a/lld/test/wasm/Inputs/locals-duplicate2.ll +++ b/lld/test/wasm/Inputs/locals-duplicate2.ll @@ -1,11 +1,11 @@ target triple = "wasm32-unknown-unknown" ; Will collide: local (internal linkage) with global (external) linkage -@colliding_global1 = default global i32 0, align 4 +@colliding_global1 = default global i32 1, align 4 ; Will collide: global with local -@colliding_global2 = internal default global i32 0, align 4 +@colliding_global2 = internal default global i32 1, align 4 ; Will collide: local with local -@colliding_global3 = internal default global i32 0, align 4 +@colliding_global3 = internal default global i32 1, align 4 ; Will collide: local with global define i32 @colliding_func1() { diff --git a/lld/test/wasm/bss-only.ll b/lld/test/wasm/bss-only.ll new file mode 100644 --- /dev/null +++ b/lld/test/wasm/bss-only.ll @@ -0,0 +1,14 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -no-gc-sections --no-entry %t.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; Test that the data section is skipped entirely when there are only +; bss segments + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +@a = global [1000 x i8] zeroinitializer, align 1 +@b = global i32 0 + +; CHECK-NOT: - Type: DATA diff --git a/lld/test/wasm/custom-section-name.ll b/lld/test/wasm/custom-section-name.ll --- a/lld/test/wasm/custom-section-name.ll +++ b/lld/test/wasm/custom-section-name.ll @@ -1,6 +1,8 @@ ; RUN: llc -filetype=obj %s -o %t.o ; RUN: wasm-ld -no-gc-sections --no-entry -o %t.wasm %t.o -; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefixes=CHECK,NO-BSS +; RUN: wasm-ld -no-gc-sections --no-entry --import-memory -o %t.bss.wasm %t.o +; RUN: obj2yaml %t.bss.wasm | FileCheck %s --check-prefixes=CHECK,BSS ; RUN: wasm-ld -no-gc-sections --no-entry -o %t_reloc.o %t.o --relocatable ; RUN: obj2yaml %t_reloc.o | FileCheck -check-prefix RELOC %s @@ -32,12 +34,13 @@ ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1032 ; CHECK-NEXT: Content: '07000000' -; CHECK-NEXT: - SectionOffset: 37 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1036 -; CHECK-NEXT: Content: '00000000' +; BSS-NEXT: - SectionOffset: 37 +; BSS-NEXT: InitFlags: 0 +; BSS-NEXT: Offset: +; BSS-NEXT: Opcode: I32_CONST +; BSS-NEXT: Value: 1036 +; BSS-NEXT: Content: '00000000' +; NO-BSS-NOT: - SectionOffset: ; RELOC-LABEL: SegmentInfo: ; RELOC-NEXT: - Index: 0 diff --git a/lld/test/wasm/data-layout.ll b/lld/test/wasm/data-layout.ll --- a/lld/test/wasm/data-layout.ll +++ b/lld/test/wasm/data-layout.ll @@ -54,12 +54,6 @@ ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1040 ; CHECK-NEXT: Content: '0100000000000000000000000000000003000000000000000004000034040000' -; CHECK-NEXT: - SectionOffset: 58 -; CHECK-NEXT: InitFlags: 0 -; CHECK-NEXT: Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1072 -; CHECK-NEXT: Content: '0000000000000000' ; CHECK-NEXT: - Type: CUSTOM diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll --- a/lld/test/wasm/data-segments.ll +++ b/lld/test/wasm/data-segments.ll @@ -44,13 +44,6 @@ ; ACTIVE-NEXT: Opcode: I32_CONST ; ACTIVE-NEXT: Value: 1040 ; ACTIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000 -; ACTIVE-NEXT: - SectionOffset: 53 -; ACTIVE-NEXT: InitFlags: 0 -; ACTIVE-NEXT: Offset: -; ACTIVE-NEXT: Opcode: I32_CONST -; ACTIVE-NEXT: Value: 1060 -; ACTIVE-NEXT: Content: '0000000000 -; ACTIVE-SAME: 0000000000' ; ACTIVE-NEXT: - Type: CUSTOM ; ACTIVE-NEXT: Name: name ; ACTIVE-NEXT: FunctionNames: @@ -78,10 +71,6 @@ ; PASSIVE-NEXT: - SectionOffset: 18 ; PASSIVE-NEXT: InitFlags: 1 ; PASSIVE-NEXT: Content: 68656C6C6F00676F6F646279650000002A000000 -; PASSIVE-NEXT: - SectionOffset: 41 -; PASSIVE-NEXT: InitFlags: 1 -; PASSIVE-NEXT: Content: '0000000000 -; PASSIVE-SAME: 0000000000' ; PASSIVE-NEXT: - Type: CUSTOM ; PASSIVE-NEXT: Name: name ; PASSIVE-NEXT: FunctionNames: diff --git a/lld/test/wasm/locals-duplicate.test b/lld/test/wasm/locals-duplicate.test --- a/lld/test/wasm/locals-duplicate.test +++ b/lld/test/wasm/locals-duplicate.test @@ -167,7 +167,7 @@ ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1024 -; CHECK-NEXT: Content: '000000000000000000000000000000000000000000000000' +; CHECK-NEXT: Content: '010000000100000001000000010000000100000001000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: @@ -299,13 +299,13 @@ ; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4190808080000B ; RELOC-NEXT: - Index: 6 -; RELOC-NEXT: Locals: +; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4181808080000B ; RELOC-NEXT: - Index: 7 -; RELOC-NEXT: Locals: +; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4182808080000B ; RELOC-NEXT: - Index: 8 -; RELOC-NEXT: Locals: +; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4183808080000B ; RELOC-NEXT: - Index: 9 ; RELOC-NEXT: Locals: @@ -326,13 +326,13 @@ ; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4194808080000B ; RELOC-NEXT: - Index: 15 -; RELOC-NEXT: Locals: +; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4184808080000B ; RELOC-NEXT: - Index: 16 -; RELOC-NEXT: Locals: +; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4185808080000B ; RELOC-NEXT: - Index: 17 -; RELOC-NEXT: Locals: +; RELOC-NEXT: Locals: ; RELOC-NEXT: Body: 4186808080000B ; RELOC-NEXT: - Type: DATA ; RELOC-NEXT: Segments: @@ -341,19 +341,19 @@ ; RELOC-NEXT: Offset: ; RELOC-NEXT: Opcode: I32_CONST ; RELOC-NEXT: Value: 0 -; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: Content: '0100000001000000' ; RELOC-NEXT: - SectionOffset: 19 ; RELOC-NEXT: InitFlags: 0 ; RELOC-NEXT: Offset: ; RELOC-NEXT: Opcode: I32_CONST ; RELOC-NEXT: Value: 8 -; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: Content: '0100000001000000' ; RELOC-NEXT: - SectionOffset: 32 ; RELOC-NEXT: InitFlags: 0 ; RELOC-NEXT: Offset: ; RELOC-NEXT: Opcode: I32_CONST ; RELOC-NEXT: Value: 16 -; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: Content: '0100000001000000' ; RELOC-NEXT: - Type: CUSTOM ; RELOC-NEXT: Name: linking ; RELOC-NEXT: Version: 2 @@ -489,15 +489,15 @@ ; RELOC-NEXT: Size: 4 ; RELOC-NEXT: SegmentInfo: ; RELOC-NEXT: - Index: 0 -; RELOC-NEXT: Name: .bss.colliding_global1 +; RELOC-NEXT: Name: .data.colliding_global1 ; RELOC-NEXT: Alignment: 2 ; RELOC-NEXT: Flags: [ ] ; RELOC-NEXT: - Index: 1 -; RELOC-NEXT: Name: .bss.colliding_global2 +; RELOC-NEXT: Name: .data.colliding_global2 ; RELOC-NEXT: Alignment: 2 ; RELOC-NEXT: Flags: [ ] ; RELOC-NEXT: - Index: 2 -; RELOC-NEXT: Name: .bss.colliding_global3 +; RELOC-NEXT: Name: .data.colliding_global3 ; RELOC-NEXT: Alignment: 2 ; RELOC-NEXT: Flags: [ ] ; RELOC-NEXT: - Type: CUSTOM diff --git a/lld/wasm/OutputSections.h b/lld/wasm/OutputSections.h --- a/lld/wasm/OutputSections.h +++ b/lld/wasm/OutputSections.h @@ -82,7 +82,7 @@ void writeTo(uint8_t *buf) override; uint32_t getNumRelocations() const override; void writeRelocations(raw_ostream &os) const override; - bool isNeeded() const override { return segments.size() > 0; } + bool isNeeded() const override; void finalizeContents() override; protected: diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -128,8 +128,11 @@ void DataSection::finalizeContents() { raw_string_ostream os(dataSectionHeader); + unsigned segmentCount = std::count_if( + segments.begin(), segments.end(), + [](OutputSegment *segment) { return !segment->isImplicit; }); - writeUleb128(os, segments.size(), "data segment count"); + writeUleb128(os, segmentCount, "data segment count"); os.flush(); bodySize = dataSectionHeader.size(); @@ -137,6 +140,8 @@ "Currenly only a single data segment is supported in PIC mode"); for (OutputSegment *segment : segments) { + if (segment->isImplicit) + continue; raw_string_ostream os(segment->header); writeUleb128(os, segment->initFlags, "init flags"); if (segment->initFlags & WASM_SEGMENT_HAS_MEMINDEX) @@ -181,6 +186,8 @@ memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size()); for (const OutputSegment *segment : segments) { + if (segment->isImplicit) + continue; // Write data segment header uint8_t *segStart = buf + segment->sectionOffset; memcpy(segStart, segment->header.data(), segment->header.size()); @@ -205,6 +212,13 @@ c->writeRelocations(os); } +bool DataSection::isNeeded() const { + return std::find_if(segments.begin(), segments.end(), + [](OutputSegment *const seg) { + return !seg->isImplicit; + }) != segments.end(); +} + void CustomSection::finalizeContents() { raw_string_ostream os(nameData); encodeULEB128(name.size(), os); diff --git a/lld/wasm/OutputSegment.h b/lld/wasm/OutputSegment.h --- a/lld/wasm/OutputSegment.h +++ b/lld/wasm/OutputSegment.h @@ -32,6 +32,7 @@ } StringRef name; + bool isImplicit = false; uint32_t index = 0; uint32_t initFlags = 0; uint32_t sectionOffset = 0; diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -250,9 +250,7 @@ class DataCountSection : public SyntheticSection { public: - DataCountSection(uint32_t numSegments) - : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), - numSegments(numSegments) {} + DataCountSection(ArrayRef segments); bool isNeeded() const override; void writeBody() override; diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -361,6 +361,12 @@ } } +DataCountSection::DataCountSection(ArrayRef segments) + : SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT), + numSegments(std::count_if( + segments.begin(), segments.end(), + [](OutputSegment *const segment) { return !segment->isImplicit; })) {} + void DataCountSection::writeBody() { writeUleb128(bodyOutputStream, numSegments, "data count"); } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -669,6 +669,13 @@ s = make(name); if (config->sharedMemory || name == ".tdata") s->initFlags = WASM_SEGMENT_IS_PASSIVE; + // Exported memories are guaranteed to be zero-initialized, so no need + // to emit data segments for bss sections. + // TODO: consider initializing bss sections with memory.fill + // instructions when memory is imported and bulk-memory is available. + if (!config->importMemory && !config->relocatable && + name.startswith(".bss")) + s->isImplicit = true; segments.push_back(s); } s->addInputSegment(segment); @@ -961,7 +968,7 @@ out.exportSec = make(); out.startSec = make(segments.size()); out.elemSec = make(); - out.dataCountSec = make(segments.size()); + out.dataCountSec = make(segments); out.linkingSec = make(initFunctions, segments); out.nameSec = make(); out.producersSec = make();