summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/test/wasm/data-segment-merging.ll137
-rw-r--r--lld/test/wasm/data-segments.ll99
-rw-r--r--lld/wasm/Config.h1
-rw-r--r--lld/wasm/Driver.cpp18
-rw-r--r--lld/wasm/MarkLive.cpp8
-rw-r--r--lld/wasm/Options.td6
-rw-r--r--lld/wasm/OutputSections.cpp28
-rw-r--r--lld/wasm/OutputSegment.h1
-rw-r--r--lld/wasm/Symbols.cpp1
-rw-r--r--lld/wasm/Symbols.h4
-rw-r--r--lld/wasm/SyntheticSections.cpp2
-rw-r--r--lld/wasm/Writer.cpp91
-rw-r--r--llvm/include/llvm/BinaryFormat/Wasm.h3
13 files changed, 329 insertions, 70 deletions
diff --git a/lld/test/wasm/data-segment-merging.ll b/lld/test/wasm/data-segment-merging.ll
index 43728a8ec44..8e4d6cc7965 100644
--- a/lld/test/wasm/data-segment-merging.ll
+++ b/lld/test/wasm/data-segment-merging.ll
@@ -8,40 +8,117 @@ target triple = "wasm32-unknown-unknown"
@e = private constant [9 x i8] c"constant\00", align 1
@f = private constant i8 43, align 4
-; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o
+; RUN: llc -mattr=+bulk-memory -filetype=obj %s -o %t.o
-; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o
+; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.o
; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE
-; MERGE-NOT: DATACOUNT
-; MERGE: - Type: DATA
-; MERGE: Segments:
-; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
-; MERGE: Content: 636F6E7374616E74000000002B
-; MERGE-NOT: Content:
+; MERGE-LABEL: - Type: DATA
+; MERGE-NEXT: Segments:
+; MERGE-NEXT: - SectionOffset: 7
+; MERGE-NEXT: InitFlags: 0
+; MERGE-NEXT: Offset:
+; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+; MERGE-NEXT: - SectionOffset: 41
+; MERGE-NEXT: InitFlags: 0
+; MERGE-NEXT: Offset:
+; MERGE: Content: 636F6E7374616E74000000002B
+; MERGE-NEXT: - Type: CUSTOM
+; MERGE-NEXT: Name: name
+; MERGE-NEXT: FunctionNames:
+; MERGE-NEXT: - Index: 0
+; MERGE-NEXT: Name: __wasm_call_ctors
+; MERGE-NOT: - Index:
-; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o
+; 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
; SEPARATE-NOT: DATACOUNT
-; SEPARATE: - Type: DATA
-; SEPARATE: Segments:
-; SEPARATE: Content: 68656C6C6F00
-; SEPARATE: Content: 676F6F6462796500
-; SEPARATE: Content: '776861746576657200'
-; SEPARATE: Content: 2A000000
-; SEPARATE: Content: 636F6E7374616E7400
-; SEPARATE: Content: 2B
-; SEPARATE-NOT: Content:
-
-; RUN: llc -filetype=obj %s -mattr=+bulk-memory -o %t.data-segment-merging.bulk-memory.o
-; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.bulk-memory.wasm %t.data-segment-merging.bulk-memory.o
-; RUN: obj2yaml %t.merged.bulk-memory.wasm | FileCheck %s --check-prefix=BULK-MEMORY
-
-; BULK-MEMORY: - Type: DATACOUNT
-; BULK-MEMORY: Count: 2
-; BULK-MEMORY: - Type: DATA
-; BULK-MEMORY: Segments:
-; BULK-MEMORY: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
-; BULK-MEMORY: Content: 636F6E7374616E74000000002B
-; BULK-MEMORY-NOT: Content:
+; SEPARATE-LABEL: - Type: DATA
+; SEPARATE-NEXT: Segments:
+; SEPARATE-NEXT: - SectionOffset: 7
+; SEPARATE-NEXT: InitFlags: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE: Content: 68656C6C6F00
+; SEPARATE-NEXT: - SectionOffset: 19
+; SEPARATE-NEXT: InitFlags: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE: Content: 676F6F6462796500
+; SEPARATE-NEXT: - SectionOffset: 33
+; SEPARATE-NEXT: InitFlags: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE: Content: '776861746576657200'
+; SEPARATE-NEXT: - SectionOffset: 48
+; SEPARATE-NEXT: InitFlags: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE: Content: 2A000000
+; SEPARATE-NEXT: - SectionOffset: 58
+; SEPARATE-NEXT: InitFlags: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE: Content: 636F6E7374616E7400
+; SEPARATE-NEXT: - SectionOffset: 73
+; SEPARATE-NEXT: InitFlags: 0
+; SEPARATE-NEXT: Offset:
+; SEPARATE: Content: 2B
+; SEPARATE-NEXT: - Type: CUSTOM
+; SEPARATE-NEXT: Name: name
+; SEPARATE-NEXT: FunctionNames:
+; SEPARATE-NEXT: - Index: 0
+; SEPARATE-NEXT: Name: __wasm_call_ctors
+; SEPARATE-NOT: - Index:
+
+; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments -o %t.merged.passive.wasm %t.o
+; RUN: obj2yaml %t.merged.passive.wasm | FileCheck %s --check-prefix=PASSIVE-MERGE
+
+; PASSIVE-MERGE-LABEL: - Type: DATACOUNT
+; PASSIVE-MERGE-NEXT: Count: 2
+; PASSIVE-MERGE-LABEL: - Type: DATA
+; PASSIVE-MERGE-NEXT: Segments:
+; PASSIVE-MERGE-NEXT: - SectionOffset: 3
+; PASSIVE-MERGE-NEXT: InitFlags: 1
+; PASSIVE-MERGE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+; PASSIVE-MERGE-NEXT: - SectionOffset: 33
+; PASSIVE-MERGE-NEXT: InitFlags: 1
+; PASSIVE-MERGE-NEXT: Content: 636F6E7374616E74000000002B
+; PASSIVE-MERGE-NEXT: - Type: CUSTOM
+; PASSIVE-MERGE-NEXT: Name: name
+; PASSIVE-MERGE-NEXT: FunctionNames:
+; PASSIVE-MERGE-NEXT: - Index: 0
+; PASSIVE-MERGE-NEXT: Name: __wasm_call_ctors
+; PASSIVE-MERGE-NEXT: - Index: 1
+; PASSIVE-MERGE-NEXT: Name: __wasm_init_memory
+; PASSIVE-MERGE-NOT: - Index:
+
+; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments -no-merge-data-segments -o %t.separate.passive.wasm %t.o
+; RUN: obj2yaml %t.separate.passive.wasm | FileCheck %s --check-prefix=PASSIVE-SEPARATE
+
+; PASSIVE-SEPARATE-LABEL: - Type: DATACOUNT
+; PASSIVE-SEPARATE-NEXT: Count: 6
+; PASSIVE-SEPARATE-LABEL: - Type: DATA
+; PASSIVE-SEPARATE-NEXT: Segments:
+; PASSIVE-SEPARATE-NEXT: - SectionOffset: 3
+; PASSIVE-SEPARATE-NEXT: InitFlags: 1
+; PASSIVE-SEPARATE-NEXT: Content: 68656C6C6F00
+; PASSIVE-SEPARATE-NEXT: - SectionOffset: 11
+; PASSIVE-SEPARATE-NEXT: InitFlags: 1
+; PASSIVE-SEPARATE-NEXT: Content: 676F6F6462796500
+; PASSIVE-SEPARATE-NEXT: - SectionOffset: 21
+; PASSIVE-SEPARATE-NEXT: InitFlags: 1
+; PASSIVE-SEPARATE-NEXT: Content: '776861746576657200'
+; PASSIVE-SEPARATE-NEXT: - SectionOffset: 32
+; PASSIVE-SEPARATE-NEXT: InitFlags: 1
+; PASSIVE-SEPARATE-NEXT: Content: 2A000000
+; PASSIVE-SEPARATE-NEXT: - SectionOffset: 38
+; PASSIVE-SEPARATE-NEXT: InitFlags: 1
+; PASSIVE-SEPARATE-NEXT: Content: 636F6E7374616E7400
+; PASSIVE-SEPARATE-NEXT: - SectionOffset: 49
+; PASSIVE-SEPARATE-NEXT: InitFlags: 1
+; PASSIVE-SEPARATE-NEXT: Content: 2B
+; PASSIVE-SEPARATE-NEXT: - Type: CUSTOM
+; PASSIVE-SEPARATE-NEXT: Name: name
+; PASSIVE-SEPARATE-NEXT: FunctionNames:
+; PASSIVE-SEPARATE-NEXT: - Index: 0
+; PASSIVE-SEPARATE-NEXT: Name: __wasm_call_ctors
+; PASSIVE-SEPARATE-NEXT: - Index: 1
+; PASSIVE-SEPARATE-NEXT: Name: __wasm_init_memory
+; PASSIVE-SEPARATE-NOT: - Index
diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll
new file mode 100644
index 00000000000..4f1d9a4a2d5
--- /dev/null
+++ b/lld/test/wasm/data-segments.ll
@@ -0,0 +1,99 @@
+; RUN: llc -filetype=obj %s -o %t.atomics.o -mattr=+atomics
+; RUN: llc -filetype=obj %s -o %t.bulk-mem.o -mattr=+bulk-memory
+; RUN: llc -filetype=obj %s -o %t.atomics.bulk-mem.o -mattr=+atomics,+bulk-memory
+
+; atomics => active segments (TODO: error)
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm
+; RUN: obj2yaml %t.atomics.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, active segments => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.o -o %t.atomics.active.wasm
+; RUN: obj2yaml %t.atomics.active.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, passive segments => error
+; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.o -o %t.atomics.passive.wasm 2>&1 | FileCheck %s --check-prefix ERROR
+
+; bulk memory => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry %t.bulk-mem.o -o %t.bulk-mem.wasm
+; RUN: obj2yaml %t.bulk-mem.wasm | FileCheck %s --check-prefix ACTIVE
+
+; bulk-memory, active segments => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry --active-segments %t.bulk-mem.o -o %t.bulk-mem.active.wasm
+; RUN: obj2yaml %t.bulk-mem.active.wasm | FileCheck %s --check-prefix ACTIVE
+
+; bulk memory, passive segments => passive segments
+; RUN: wasm-ld -no-gc-sections --no-entry --passive-segments %t.bulk-mem.o -o %t.bulk-mem.passive.wasm
+; RUN: obj2yaml %t.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE
+
+; atomics, bulk memory => active segments (TODO: passive)
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.wasm
+; RUN: obj2yaml %t.atomics.bulk-mem.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, bulk memory, active segments => active segments
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --active-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.active.wasm
+; RUN: obj2yaml %t.atomics.bulk-mem.active.wasm | FileCheck %s --check-prefix ACTIVE
+
+; atomics, bulk memory, passive segments => passive segments
+; RUN: wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 --passive-segments %t.atomics.bulk-mem.o -o %t.atomics.bulk-mem.passive.wasm
+; RUN: obj2yaml %t.atomics.bulk-mem.passive.wasm | FileCheck %s --check-prefix PASSIVE
+
+target triple = "wasm32-unknown-unknown"
+
+@a = hidden global [6 x i8] c"hello\00", align 1
+@b = hidden global [8 x i8] c"goodbye\00", align 1
+@c = hidden global [9 x i8] c"whatever\00", align 1
+@d = hidden global i32 42, align 4
+
+@e = private constant [9 x i8] c"constant\00", align 1
+@f = private constant i8 43, align 4
+
+; ERROR: 'bulk-memory' feature must be used in order to emit passive segments
+
+; ACTIVE-LABEL: - Type: CODE
+; ACTIVE-NEXT: Functions:
+; ACTIVE-NEXT: - Index: 0
+; ACTIVE-NEXT: Locals: []
+; ACTIVE-NEXT: Body: 0B
+; ACTIVE-NEXT: - Type: DATA
+; ACTIVE-NEXT: Segments:
+; ACTIVE-NEXT: - SectionOffset: 7
+; ACTIVE-NEXT: InitFlags: 0
+; ACTIVE-NEXT: Offset:
+; ACTIVE-NEXT: Opcode: I32_CONST
+; ACTIVE-NEXT: Value: 1024
+; ACTIVE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+; ACTIVE-NEXT: - SectionOffset: 41
+; ACTIVE-NEXT: InitFlags: 0
+; ACTIVE-NEXT: Offset:
+; ACTIVE-NEXT: Opcode: I32_CONST
+; ACTIVE-NEXT: Value: 1052
+; ACTIVE-NEXT: Content: 636F6E7374616E74000000002B
+; ACTIVE-NEXT: - Type: CUSTOM
+; ACTIVE-NEXT: Name: name
+; ACTIVE-NEXT: FunctionNames:
+; ACTIVE-NEXT: - Index: 0
+; ACTIVE-NEXT: Name: __wasm_call_ctors
+
+; PASSIVE-LABEL: - Type: CODE
+; PASSIVE-NEXT: Functions:
+; PASSIVE-NEXT: - Index: 0
+; PASSIVE-NEXT: Locals: []
+; PASSIVE-NEXT: Body: 10010B
+; PASSIVE-NEXT: - Index: 1
+; PASSIVE-NEXT: Locals: []
+; PASSIVE-NEXT: Body: 4180084100411CFC080000FC0900419C084100410DFC080100FC09010B
+; PASSIVE-NEXT: - Type: DATA
+; PASSIVE-NEXT: Segments:
+; PASSIVE-NEXT: - SectionOffset: 3
+; PASSIVE-NEXT: InitFlags: 1
+; PASSIVE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+; PASSIVE-NEXT: - SectionOffset: 33
+; PASSIVE-NEXT: InitFlags: 1
+; PASSIVE-NEXT: Content: 636F6E7374616E74000000002B
+; PASSIVE-NEXT: - Type: CUSTOM
+; PASSIVE-NEXT: Name: name
+; PASSIVE-NEXT: FunctionNames:
+; PASSIVE-NEXT: - Index: 0
+; PASSIVE-NEXT: Name: __wasm_call_ctors
+; PASSIVE-NEXT: - Index: 1
+; PASSIVE-NEXT: Name: __wasm_init_memory
diff --git a/lld/wasm/Config.h b/lld/wasm/Config.h
index b6e72dcc721..b63044852d5 100644
--- a/lld/wasm/Config.h
+++ b/lld/wasm/Config.h
@@ -34,6 +34,7 @@ struct Configuration {
bool GcSections;
bool ImportMemory;
bool SharedMemory;
+ bool PassiveSegments;
bool ImportTable;
bool MergeDataSegments;
bool Pie;
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 6c5c72df94d..307213e8d1b 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -320,6 +320,9 @@ static void readConfigs(opt::InputArgList &Args) {
Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
Config->ImportMemory = Args.hasArg(OPT_import_memory);
Config->SharedMemory = Args.hasArg(OPT_shared_memory);
+ // TODO: Make passive segments the default with shared memory
+ Config->PassiveSegments =
+ Args.hasFlag(OPT_passive_segments, OPT_active_segments, false);
Config->ImportTable = Args.hasArg(OPT_import_table);
Config->LTOO = args::getInteger(Args, OPT_lto_O, 2);
Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1);
@@ -460,10 +463,19 @@ static void createSyntheticSymbols() {
"__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
+ if (Config->PassiveSegments) {
+ // Passive segments are used to avoid memory being reinitialized on each
+ // thread's instantiation. These passive segments are initialized and
+ // dropped in __wasm_init_memory, which is the first function called from
+ // __wasm_call_ctors.
+ WasmSym::InitMemory = Symtab->addSyntheticFunction(
+ "__wasm_init_memory", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(NullSignature, "__wasm_init_memory"));
+ }
+
if (Config->Pic) {
- // For PIC code we create a synthetic function call __wasm_apply_relocs
- // and add this as the first call in __wasm_call_ctors.
- // We also unconditionally export
+ // For PIC code we create a synthetic function __wasm_apply_relocs which
+ // is called from __wasm_call_ctors before the user-level constructors.
WasmSym::ApplyRelocs = Symtab->addSyntheticFunction(
"__wasm_apply_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN,
make<SyntheticFunction>(NullSignature, "__wasm_apply_relocs"));
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index b3dce23bcaa..08264925a7f 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -50,6 +50,10 @@ void lld::wasm::markLive() {
// function. However, this function does not contain relocations so we
// have to manually mark the ctors as live if CallCtors itself is live.
if (Sym == WasmSym::CallCtors) {
+ if (Config->PassiveSegments)
+ Enqueue(WasmSym::InitMemory);
+ if (Config->Pic)
+ Enqueue(WasmSym::ApplyRelocs);
for (const ObjFile *Obj : Symtab->ObjectFiles) {
const WasmLinkingData &L = Obj->getWasmObj()->linkingData();
for (const WasmInitFunc &F : L.InitFunctions) {
@@ -79,10 +83,8 @@ void lld::wasm::markLive() {
}
}
- if (Config->Pic) {
+ if (Config->Pic)
Enqueue(WasmSym::CallCtors);
- Enqueue(WasmSym::ApplyRelocs);
- }
// Follow relocations to mark all reachable chunks.
while (!Q.empty()) {
diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td
index b6fe25d5d25..29bd9d9ef3d 100644
--- a/lld/wasm/Options.td
+++ b/lld/wasm/Options.td
@@ -143,6 +143,12 @@ def import_memory: F<"import-memory">,
def shared_memory: F<"shared-memory">,
HelpText<"Use shared linear memory">;
+def active_segments: F<"active-segments">,
+ HelpText<"Force segments to be active">;
+
+def passive_segments: F<"passive-segments">,
+ HelpText<"Force segments to be passive">;
+
def import_table: F<"import-table">,
HelpText<"Import function table from the environment">;
diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp
index 338c88bc634..c81d0963aba 100644
--- a/lld/wasm/OutputSections.cpp
+++ b/lld/wasm/OutputSections.cpp
@@ -132,20 +132,26 @@ void DataSection::finalizeContents() {
OS.flush();
BodySize = DataSectionHeader.size();
+ assert(!Config->Pic ||
+ Segments.size() <= 1 &&
+ "Currenly only a single data segment is supported in PIC mode");
+
for (OutputSegment *Segment : Segments) {
raw_string_ostream OS(Segment->Header);
- writeUleb128(OS, 0, "memory index");
- WasmInitExpr InitExpr;
- if (Config->Pic) {
- assert(Segments.size() <= 1 &&
- "Currenly only a single data segment is supported in PIC mode");
- InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
- InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
- } else {
- InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InitExpr.Value.Int32 = Segment->StartVA;
+ writeUleb128(OS, Segment->InitFlags, "init flags");
+ if (Segment->InitFlags & WASM_SEGMENT_HAS_MEMINDEX)
+ writeUleb128(OS, 0, "memory index");
+ if ((Segment->InitFlags & WASM_SEGMENT_IS_PASSIVE) == 0) {
+ WasmInitExpr InitExpr;
+ if (Config->Pic) {
+ InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
+ InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
+ } else {
+ InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ InitExpr.Value.Int32 = Segment->StartVA;
+ }
+ writeInitExpr(OS, InitExpr);
}
- writeInitExpr(OS, InitExpr);
writeUleb128(OS, Segment->Size, "segment size");
OS.flush();
diff --git a/lld/wasm/OutputSegment.h b/lld/wasm/OutputSegment.h
index 782b43bd7ee..a9679c1d675 100644
--- a/lld/wasm/OutputSegment.h
+++ b/lld/wasm/OutputSegment.h
@@ -33,6 +33,7 @@ public:
StringRef Name;
const uint32_t Index;
+ uint32_t InitFlags = 0;
uint32_t SectionOffset = 0;
uint32_t Alignment = 0;
uint32_t StartVA = 0;
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index d6efc364a0a..941f500732b 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -25,6 +25,7 @@ using namespace lld;
using namespace lld::wasm;
DefinedFunction *WasmSym::CallCtors;
+DefinedFunction *WasmSym::InitMemory;
DefinedFunction *WasmSym::ApplyRelocs;
DefinedData *WasmSym::DsoHandle;
DefinedData *WasmSym::DataEnd;
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 5a340350eef..1745614bb1d 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -438,6 +438,10 @@ struct WasmSym {
// Function that directly calls all ctors in priority order.
static DefinedFunction *CallCtors;
+ // __wasm_init_memory
+ // Function that initializes passive data segments post-instantiation.
+ static DefinedFunction *InitMemory;
+
// __wasm_apply_relocs
// Function that applies relocations to data segment post-instantiation.
static DefinedFunction *ApplyRelocs;
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index 198e6dbdffe..2480ff2a044 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -323,7 +323,7 @@ void DataCountSection::writeBody() {
}
bool DataCountSection::isNeeded() const {
- return NumSegments && Out.TargetFeaturesSec->Features.count("bulk-memory");
+ return NumSegments && Config->PassiveSegments;
}
static uint32_t getWasmFlags(const Symbol *Sym) {
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 7c91eacadab..09a14307a6e 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -54,6 +54,7 @@ public:
private:
void openFile();
+ void createInitMemoryFunction();
void createApplyRelocationsFunction();
void createCallCtorsFunction();
@@ -407,6 +408,10 @@ void Writer::populateTargetFeatures() {
error("'atomics' feature is disallowed by " + Disallowed["atomics"] +
", so --shared-memory must not be used");
+ if (!Used.count("bulk-memory") && Config->PassiveSegments)
+ error("'bulk-memory' feature must be used in order to emit passive "
+ "segments");
+
// Validate that used features are allowed in output
if (!InferFeatures) {
for (auto &Feature : Used.keys()) {
@@ -621,6 +626,8 @@ void Writer::createOutputSegments() {
if (S == nullptr) {
LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n");
S = make<OutputSegment>(Name, Segments.size());
+ if (Config->PassiveSegments)
+ S->InitFlags = WASM_SEGMENT_IS_PASSIVE;
Segments.push_back(S);
}
S->addInputSegment(Segment);
@@ -629,10 +636,57 @@ void Writer::createOutputSegments() {
}
}
+static void CreateFunction(DefinedFunction *Func, StringRef BodyContent) {
+ std::string FunctionBody;
+ {
+ raw_string_ostream OS(FunctionBody);
+ writeUleb128(OS, BodyContent.size(), "function size");
+ OS << BodyContent;
+ }
+ ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
+ cast<SyntheticFunction>(Func->Function)->setBody(Body);
+}
+
+void Writer::createInitMemoryFunction() {
+ LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n");
+ std::string BodyContent;
+ {
+ raw_string_ostream OS(BodyContent);
+ writeUleb128(OS, 0, "num locals");
+
+ // initialize passive data segments
+ for (const OutputSegment *S : Segments) {
+ if (S->InitFlags & WASM_SEGMENT_IS_PASSIVE) {
+ // destination address
+ writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const");
+ writeUleb128(OS, S->StartVA, "destination address");
+ // source segment offset
+ writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const");
+ writeUleb128(OS, 0, "segment offset");
+ // memory region size
+ writeU8(OS, WASM_OPCODE_I32_CONST, "i32.const");
+ writeUleb128(OS, S->Size, "memory region size");
+ // memory.init instruction
+ writeU8(OS, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
+ writeUleb128(OS, WASM_OPCODE_MEMORY_INIT, "MEMORY.INIT");
+ writeUleb128(OS, S->Index, "segment index immediate");
+ writeU8(OS, 0, "memory index immediate");
+ // data.drop instruction
+ writeU8(OS, WASM_OPCODE_MISC_PREFIX, "bulk-memory prefix");
+ writeUleb128(OS, WASM_OPCODE_DATA_DROP, "DATA.DROP");
+ writeUleb128(OS, S->Index, "segment index immediate");
+ }
+ }
+ writeU8(OS, WASM_OPCODE_END, "END");
+ }
+
+ CreateFunction(WasmSym::InitMemory, BodyContent);
+}
+
// For -shared (PIC) output, we create create a synthetic function which will
// apply any relocations to the data segments on startup. This function is
-// called __wasm_apply_relocs and is added at the very beginning of
-// __wasm_call_ctors before any of the constructors run.
+// called __wasm_apply_relocs and is added at the beginning of __wasm_call_ctors
+// before any of the constructors run.
void Writer::createApplyRelocationsFunction() {
LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
// First write the body's contents to a string.
@@ -646,16 +700,7 @@ void Writer::createApplyRelocationsFunction() {
writeU8(OS, WASM_OPCODE_END, "END");
}
- // Once we know the size of the body we can create the final function body
- std::string FunctionBody;
- {
- raw_string_ostream OS(FunctionBody);
- writeUleb128(OS, BodyContent.size(), "function size");
- OS << BodyContent;
- }
-
- ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
- cast<SyntheticFunction>(WasmSym::ApplyRelocs->Function)->setBody(Body);
+ CreateFunction(WasmSym::ApplyRelocs, BodyContent);
}
// Create synthetic "__wasm_call_ctors" function based on ctor functions
@@ -669,11 +714,20 @@ void Writer::createCallCtorsFunction() {
{
raw_string_ostream OS(BodyContent);
writeUleb128(OS, 0, "num locals");
+
+ if (Config->PassiveSegments) {
+ writeU8(OS, WASM_OPCODE_CALL, "CALL");
+ writeUleb128(OS, WasmSym::InitMemory->getFunctionIndex(),
+ "function index");
+ }
+
if (Config->Pic) {
writeU8(OS, WASM_OPCODE_CALL, "CALL");
writeUleb128(OS, WasmSym::ApplyRelocs->getFunctionIndex(),
"function index");
}
+
+ // Call constructors
for (const WasmInitEntry &F : InitFunctions) {
writeU8(OS, WASM_OPCODE_CALL, "CALL");
writeUleb128(OS, F.Sym->getFunctionIndex(), "function index");
@@ -681,16 +735,7 @@ void Writer::createCallCtorsFunction() {
writeU8(OS, WASM_OPCODE_END, "END");
}
- // Once we know the size of the body we can create the final function body
- std::string FunctionBody;
- {
- raw_string_ostream OS(FunctionBody);
- writeUleb128(OS, BodyContent.size(), "function size");
- OS << BodyContent;
- }
-
- ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
- cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body);
+ CreateFunction(WasmSym::CallCtors, BodyContent);
}
// Populate InitFunctions vector with init functions from all input objects.
@@ -779,6 +824,8 @@ void Writer::run() {
if (!Config->Relocatable) {
// Create linker synthesized functions
+ if (Config->PassiveSegments)
+ createInitMemoryFunction();
if (Config->Pic)
createApplyRelocationsFunction();
createCallCtorsFunction();
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 0f327c188bf..0ff52cbdb33 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -249,6 +249,9 @@ enum : unsigned {
WASM_OPCODE_F32_CONST = 0x43,
WASM_OPCODE_F64_CONST = 0x44,
WASM_OPCODE_I32_ADD = 0x6a,
+ WASM_OPCODE_MISC_PREFIX = 0xfc,
+ WASM_OPCODE_MEMORY_INIT = 0x08,
+ WASM_OPCODE_DATA_DROP = 0x09,
};
enum : unsigned {
OpenPOWER on IntegriCloud