Skip to content

Commit

Permalink
[lld][WebAssembly] Initialize bss segments using memory.fill
Browse files Browse the repository at this point in the history
Previously we were relying on the dynamic loader to take care of this
but it simple and correct for us to do it here instead.

Now we initialize bss segments as part of `__wasm_init_memory` at the
same time we initialize passive segments.

In addition we extent the us of `__wasm_init_memory` outside of shared
memory situations.  Specifically it is now used to initialize bss
segments when the memory is imported.

Differential Revision: https://reviews.llvm.org/D112667
  • Loading branch information
sbc100 committed Oct 29, 2021
1 parent b65f24a commit 1eb79e7
Show file tree
Hide file tree
Showing 9 changed files with 257 additions and 127 deletions.
7 changes: 7 additions & 0 deletions lld/test/wasm/data-segments.ll
Expand Up @@ -187,6 +187,13 @@
; DIS-NEXT: i32.const 0
; DIS-NEXT: i32.const 20
; DIS-NEXT: memory.init 1, 0
; NOPIC-DIS-NEXT: [[PTR]].const 1060
; PIC-DIS-NEXT: [[PTR]].const 36
; PIC-DIS-NEXT: global.get 1
; PIC-DIS-NEXT: [[PTR]].add
; DIS-NEXT: i32.const 0
; DIS-NEXT: i32.const 10000
; DIS-NEXT: memory.fill 0

; NOPIC-DIS-NEXT: [[PTR]].const 11060
; PIC-DIS-NEXT: local.get 0
Expand Down
72 changes: 72 additions & 0 deletions lld/test/wasm/shared-memory-bss.s
@@ -0,0 +1,72 @@
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
# RUN: wasm-ld --experimental-pic -shared --shared-memory -o %t.so %t.o
# RUN: llvm-objdump -d --no-show-raw-insn --no-leading-addr %t.so | FileCheck %s
# RUN: obj2yaml %t.so | FileCheck %s --check-prefix=YAML

.section .bss.foo,"",@
.globl foo
.p2align 2
foo:
.int32 0
.size foo, 4

.section .data.bar,"",@
.globl bar
.p2align 2
bar:
.int32 42
.size bar, 4

.section .custom_section.target_features,"",@
.int8 2
.int8 43
.int8 7
.ascii "atomics"
.int8 43
.int8 11
.ascii "bulk-memory"

# Verify that there is only a single data segment and no bss
# in the binary:

# YAML: - Type: DATA{{$}}
# YAML-NEXT: Segments:
# YAML-NEXT: - SectionOffset: 3
# YAML-NEXT: InitFlags: 1
# YAML-NEXT: Content: 2A000000
# YAML-NEXT: - Type: CUSTOM

# CHECK: <__wasm_init_memory>:
# CHECK-NEXT: .local i32
# CHECK-NEXT: global.get 0
# CHECK-NEXT: i32.const 8
# CHECK-NEXT: i32.add
# CHECK-NEXT: local.set 0
# CHECK-NEXT: block
# CHECK-NEXT: block
# CHECK-NEXT: block
# CHECK-NEXT: local.get 0
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: i32.const 1
# CHECK-NEXT: i32.atomic.rmw.cmpxchg 0
# CHECK-NEXT: br_table {0, 1, 2} # 1: down to label1
# CHECK-NEXT: # 2: down to label0
# CHECK-NEXT: end

# Regular data gets initialized with memory.init

# CHECK-NEXT: i32.const 0
# CHECK-NEXT: global.get 0
# CHECK-NEXT: i32.add
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: i32.const 4
# CHECK-NEXT: memory.init 0, 0

# BSS gets initialized with memory.fill

# CHECK-NEXT: i32.const 4
# CHECK-NEXT: global.get 0
# CHECK-NEXT: i32.add
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: i32.const 4
# CHECK-NEXT: memory.fill 0
2 changes: 1 addition & 1 deletion lld/test/wasm/tls.s
Expand Up @@ -87,7 +87,7 @@ tls3:
# CHECK-NEXT: Mutable: true
# CHECK-NEXT: InitExpr:
# CHECK-NEXT: Opcode: I32_CONST
# CHECK-NEXT: Value: 66576
# CHECK-NEXT: Value: 66592

# __tls_base
# CHECK-NEXT: - Index: 1
Expand Down
4 changes: 4 additions & 0 deletions lld/wasm/Config.h
Expand Up @@ -91,6 +91,10 @@ struct Configuration {
// for shared libraries (since they always added to a dynamic offset at
// runtime).
uint32_t tableBase = 0;

// Will be set to true if bss data segments should be emitted. In most cases
// this is not necessary.
bool emitBssSegments = false;
};

// The only instance of Configuration struct.
Expand Down
13 changes: 6 additions & 7 deletions lld/wasm/OutputSections.cpp
Expand Up @@ -133,10 +133,9 @@ void CodeSection::writeRelocations(raw_ostream &os) const {

void DataSection::finalizeContents() {
raw_string_ostream os(dataSectionHeader);
unsigned segmentCount =
std::count_if(segments.begin(), segments.end(),
[](OutputSegment *segment) { return !segment->isBss; });

unsigned segmentCount = std::count_if(
segments.begin(), segments.end(),
[](OutputSegment *segment) { return segment->requiredInBinary(); });
#ifndef NDEBUG
unsigned activeCount = std::count_if(
segments.begin(), segments.end(), [](OutputSegment *segment) {
Expand All @@ -152,7 +151,7 @@ void DataSection::finalizeContents() {
bodySize = dataSectionHeader.size();

for (OutputSegment *segment : segments) {
if (segment->isBss)
if (!segment->requiredInBinary())
continue;
raw_string_ostream os(segment->header);
writeUleb128(os, segment->initFlags, "init flags");
Expand Down Expand Up @@ -199,7 +198,7 @@ void DataSection::writeTo(uint8_t *buf) {
memcpy(buf, dataSectionHeader.data(), dataSectionHeader.size());

for (const OutputSegment *segment : segments) {
if (segment->isBss)
if (!segment->requiredInBinary())
continue;
// Write data segment header
uint8_t *segStart = buf + segment->sectionOffset;
Expand Down Expand Up @@ -227,7 +226,7 @@ void DataSection::writeRelocations(raw_ostream &os) const {

bool DataSection::isNeeded() const {
for (const OutputSegment *seg : segments)
if (!seg->isBss)
if (seg->requiredInBinary())
return true;
return false;
}
Expand Down
5 changes: 5 additions & 0 deletions lld/wasm/OutputSegment.h
Expand Up @@ -24,6 +24,11 @@ class OutputSegment {

void addInputSegment(InputChunk *inSeg);
void finalizeInputSegments();
// In most circumstances BSS segments don't need to be written
// to the output binary. However if the memory is imported, and
// we can't use memory.fill during startup (due to lack of bulk
// memory feature) then we include BSS segments verbatim.
bool requiredInBinary() const { return !isBss || config->emitBssSegments; }

bool isTLS() const { return name == ".tdata"; }

Expand Down
11 changes: 6 additions & 5 deletions lld/wasm/SyntheticSections.cpp
Expand Up @@ -558,9 +558,10 @@ void ElemSection::writeBody() {

DataCountSection::DataCountSection(ArrayRef<OutputSegment *> segments)
: SyntheticSection(llvm::wasm::WASM_SEC_DATACOUNT),
numSegments(std::count_if(
segments.begin(), segments.end(),
[](OutputSegment *const segment) { return !segment->isBss; })) {}
numSegments(std::count_if(segments.begin(), segments.end(),
[](OutputSegment *const segment) {
return segment->requiredInBinary();
})) {}

void DataCountSection::writeBody() {
writeUleb128(bodyOutputStream, numSegments, "data count");
Expand Down Expand Up @@ -716,7 +717,7 @@ unsigned NameSection::numNamedDataSegments() const {
unsigned numNames = 0;

for (const OutputSegment *s : segments)
if (!s->name.empty() && !s->isBss)
if (!s->name.empty() && s->requiredInBinary())
++numNames;

return numNames;
Expand Down Expand Up @@ -789,7 +790,7 @@ void NameSection::writeBody() {
writeUleb128(sub.os, count, "name count");

for (OutputSegment *s : segments) {
if (!s->name.empty() && !s->isBss) {
if (!s->name.empty() && s->requiredInBinary()) {
writeUleb128(sub.os, s->index, "global index");
writeStr(sub.os, s->name, "segment name");
}
Expand Down

0 comments on commit 1eb79e7

Please sign in to comment.