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 @@ -9,23 +9,80 @@ @f = private constant i8 43, align 4 ; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o +; RUN: llc -filetype=obj %s -o %t.data-segment-merging.atomics.o -mattr=+atomics -; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o -; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE -; MERGE: - Type: DATA -; MERGE: Segments: -; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 -; MERGE: Content: 636F6E7374616E74000000002B -; MERGE-NOT: Content: - -; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o -; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE -; 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: wasm-ld -no-gc-sections --no-entry --export=__wasm_call_ctors -o - %t.data-segment-merging.o | obj2yaml | FileCheck %s --check-prefix MERGE + +; MERGE: - Type: CODE +; MERGE-NEXT: Functions: +; MERGE-NEXT: - Index: 0 +; MERGE-NEXT: Locals: [] +; MERGE-NEXT: Body: 0B +; MERGE: - Type: DATA +; MERGE: Segments: +; MERGE: InitFlags: 0 +; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 +; MERGE: InitFlags: 0 +; MERGE: Content: 636F6E7374616E74000000002B +; MERGE-NOT: Content: + +; RUN: wasm-ld -no-gc-sections --no-entry --export=__wasm_call_ctors --shared-memory --max-memory=131072 -o - %t.data-segment-merging.atomics.o | obj2yaml | FileCheck %s --check-prefix MERGE-SHARED + +; MERGE-SHARED: - Type: CODE +; MERGE-SHARED-NEXT: Functions: +; MERGE-SHARED-NEXT: - Index: 0 +; MERGE-SHARED-NEXT: Locals: [] +; MERGE-SHARED-NEXT: Body: 4180084100411CFC080000419C084100410DFC0801000B +; MERGE-SHARED: - Type: DATA +; MERGE-SHARED: Segments: +; MERGE-SHARED: InitFlags: 1 +; MERGE-SHARED: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 +; MERGE-SHARED: InitFlags: 1 +; MERGE-SHARED: Content: 636F6E7374616E74000000002B +; MERGE-SHARED-NOT: Content: + +; RUN: wasm-ld -no-gc-sections --no-entry --export=__wasm_call_ctors --no-merge-data-segments -o - %t.data-segment-merging.o | obj2yaml | FileCheck %s --check-prefix SEPARATE + +; SEPARATE: - Type: CODE +; SEPARATE-NEXT: Functions: +; SEPARATE-NEXT: - Index: 0 +; SEPARATE-NEXT: Locals: [] +; SEPARATE-NEXT: Body: 0B +; SEPARATE: - Type: DATA +; SEPARATE: Segments: +; SEPARATE: InitFlags: 0 +; SEPARATE: Content: 68656C6C6F00 +; SEPARATE: InitFlags: 0 +; SEPARATE: Content: 676F6F6462796500 +; SEPARATE: InitFlags: 0 +; SEPARATE: Content: '776861746576657200' +; SEPARATE: InitFlags: 0 +; SEPARATE: Content: 2A000000 +; SEPARATE: InitFlags: 0 +; SEPARATE: Content: 636F6E7374616E7400 +; SEPARATE: InitFlags: 0 +; SEPARATE: Content: 2B +; SEPARATE-NOT: Content: + +; RUN: wasm-ld -no-gc-sections --no-entry --export=__wasm_call_ctors --no-merge-data-segments --shared-memory --max-memory=131072 -o - %t.data-segment-merging.atomics.o | obj2yaml | FileCheck %s --check-prefix SEPARATE-SHARED + +; SEPARATE-SHARED: - Type: CODE +; SEPARATE-SHARED-NEXT: Functions: +; SEPARATE-SHARED-NEXT: - Index: 0 +; SEPARATE-SHARED-NEXT: Locals: [] +; SEPARATE-SHARED-NEXT: Body: 41800841004106FC08000041860841004108FC080100418E0841004109FC08020041980841004104FC080300419C0841004109FC08040041A80841004101FC0805000B +; SEPARATE-SHARED: - Type: DATA +; SEPARATE-SHARED: Segments: +; SEPARATE-SHARED: InitFlags: 1 +; SEPARATE-SHARED: Content: 68656C6C6F00 +; SEPARATE-SHARED: InitFlags: 1 +; SEPARATE-SHARED: Content: 676F6F6462796500 +; SEPARATE-SHARED: InitFlags: 1 +; SEPARATE-SHARED: Content: '776861746576657200' +; SEPARATE-SHARED: InitFlags: 1 +; SEPARATE-SHARED: Content: 2A000000 +; SEPARATE-SHARED: InitFlags: 1 +; SEPARATE-SHARED: Content: 636F6E7374616E7400 +; SEPARATE-SHARED: InitFlags: 1 +; SEPARATE-SHARED: Content: 2B +; SEPARATE-SHARED-NOT: Content: diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -136,18 +136,22 @@ 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) { + 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; + } + 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/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1264,6 +1264,8 @@ if (S == nullptr) { LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n"); S = make(Name, Segments.size()); + if (Config->SharedMemory) + S->InitFlags = WASM_SEGMENT_IS_PASSIVE; Segments.push_back(S); } S->addInputSegment(Segment); @@ -1274,6 +1276,8 @@ static const int OPCODE_CALL = 0x10; static const int OPCODE_END = 0xb; +static const int BULK_MEMORY_PREFIX = 0xfc; +static const int OPCODE_MEMORY_INIT = 0x08; // Create synthetic "__wasm_call_ctors" function based on ctor functions // in input object. @@ -1286,6 +1290,28 @@ { 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, BULK_MEMORY_PREFIX, "bulk-memory prefix"); + writeUleb128(OS, OPCODE_MEMORY_INIT, "MEMORY.INIT"); + writeUleb128(OS, S->Index, "segment index immediate"); + writeU8(OS, 0, "memory index immediate"); + } + } + + // call constructors for (const WasmInitEntry &F : InitFunctions) { writeU8(OS, OPCODE_CALL, "CALL"); writeUleb128(OS, F.Sym->getFunctionIndex(), "function index"); @@ -1346,14 +1372,14 @@ calculateImports(); log("-- assignIndexes"); assignIndexes(); - log("-- calculateInitFunctions"); - calculateInitFunctions(); - if (!Config->Relocatable) - createCtorFunction(); log("-- calculateTypes"); calculateTypes(); log("-- layoutMemory"); layoutMemory(); + log("-- calculateInitFunctions"); + calculateInitFunctions(); + if (!Config->Relocatable) + createCtorFunction(); log("-- calculateExports"); calculateExports(); log("-- calculateCustomSections");