diff --git a/lld/test/wasm/data-segment-merging.ll b/lld/test/wasm/data-segment-merging.ll --- a/lld/test/wasm/data-segment-merging.ll +++ b/lld/test/wasm/data-segment-merging.ll @@ -8,40 +8,117 @@ @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 --- /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 --- a/lld/wasm/Config.h +++ b/lld/wasm/Config.h @@ -34,6 +34,7 @@ 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 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -320,6 +320,9 @@ 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,20 @@ "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, make(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(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. + // We also unconditionally export WasmSym::ApplyRelocs = Symtab->addSyntheticFunction( "__wasm_apply_relocs", WASM_SYMBOL_VISIBILITY_HIDDEN, make(NullSignature, "__wasm_apply_relocs")); diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp --- a/lld/wasm/MarkLive.cpp +++ b/lld/wasm/MarkLive.cpp @@ -50,6 +50,10 @@ // 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 @@ } } - 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 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -143,6 +143,12 @@ 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 --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -132,20 +132,26 @@ 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 --- a/lld/wasm/OutputSegment.h +++ b/lld/wasm/OutputSegment.h @@ -33,6 +33,7 @@ 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.h b/lld/wasm/Symbols.h --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -438,6 +438,10 @@ // 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/Symbols.cpp b/lld/wasm/Symbols.cpp --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -25,6 +25,7 @@ using namespace lld::wasm; DefinedFunction *WasmSym::CallCtors; +DefinedFunction *WasmSym::InitMemory; DefinedFunction *WasmSym::ApplyRelocs; DefinedData *WasmSym::DsoHandle; DefinedData *WasmSym::DataEnd; diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -323,7 +323,7 @@ } 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 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -54,6 +54,7 @@ private: void openFile(); + void createInitMemoryFunction(); void createApplyRelocationsFunction(); void createCallCtorsFunction(); @@ -407,6 +408,10 @@ 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 @@ if (S == nullptr) { LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n"); S = make(Name, Segments.size()); + if (Config->PassiveSegments) + S->InitFlags = WASM_SEGMENT_IS_PASSIVE; Segments.push_back(S); } S->addInputSegment(Segment); @@ -629,10 +636,58 @@ } } +static void CreateFunction(DefinedFunction *Func, + const std::string &BodyContent) { + std::string FunctionBody; + { + raw_string_ostream OS(FunctionBody); + writeUleb128(OS, BodyContent.size(), "function size"); + OS << BodyContent; + } + ArrayRef Body = arrayRefFromStringRef(Saver.save(FunctionBody)); + cast(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 +701,7 @@ 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 Body = arrayRefFromStringRef(Saver.save(FunctionBody)); - cast(WasmSym::ApplyRelocs->Function)->setBody(Body); + CreateFunction(WasmSym::ApplyRelocs, BodyContent); } // Create synthetic "__wasm_call_ctors" function based on ctor functions @@ -669,11 +715,20 @@ { 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 +736,7 @@ 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 Body = arrayRefFromStringRef(Saver.save(FunctionBody)); - cast(WasmSym::CallCtors->Function)->setBody(Body); + CreateFunction(WasmSym::CallCtors, BodyContent); } // Populate InitFunctions vector with init functions from all input objects. @@ -779,6 +825,8 @@ 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 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -249,6 +249,9 @@ 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 {