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 @@ -2,6 +2,8 @@ ; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t.bulk-mem.o -mattr=+bulk-memory ; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem.o -mattr=+atomics,+bulk-memory ; RUN: llc --mtriple=wasm64-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem64.o -mattr=+atomics,+bulk-memory +; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem.pic.o -relocation-model=pic -mattr=+atomics,+bulk-memory,+mutable-globals +; RUN: llc --mtriple=wasm64-unknown-unknown -filetype=obj %s -o %t.atomics.bulk-mem.pic-mem64.o -relocation-model=pic -mattr=+atomics,+bulk-memory,+mutable-globals ; atomics, shared memory => error ; RUN: not wasm-ld -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.o -o %t.atomics.wasm 2>&1 | FileCheck %s --check-prefix ERROR @@ -19,8 +21,12 @@ ; RUN: obj2yaml %t.atomics.bulk-mem64.wasm | FileCheck %s --check-prefixes PASSIVE,PASSIVE64 ; Also test in combination with PIC/pie -; RUN: llc --mtriple=wasm32-unknown-unknown -filetype=obj -relocation-model=pic %s -o %t.atomics.bulk-mem.pic.o -mattr=+atomics,+bulk-memory,+mutable-globals ; RUN: wasm-ld --experimental-pic -pie -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.pic.o -o %t.pic.wasm +; RUN: obj2yaml %t.pic.wasm | FileCheck %s --check-prefixes PASSIVE-PIC,PASSIVE32-PIC + +; Also test in combination with PIC/pie + wasm64 +; RUN: wasm-ld -mwasm64 --experimental-pic -pie -no-gc-sections --no-entry --shared-memory --max-memory=131072 %t.atomics.bulk-mem.pic-mem64.o -o %t.pic-mem64.wasm +; RUN: obj2yaml %t.pic-mem64.wasm | FileCheck %s --check-prefixes PASSIVE-PIC,PASSIVE64-PIC @a = hidden global [6 x i8] c"hello\00", align 1 @b = hidden global [8 x i8] c"goodbye\00", align 1 @@ -91,3 +97,42 @@ ; PASSIVE-NEXT: Name: __wasm_init_memory ; PASSIVE-NEXT: - Index: 2 ; PASSIVE-NEXT: Name: __wasm_init_tls + +; PASSIVE-PIC: - Type: START +; PASSIVE-PIC-NEXT: StartFunction: 2 +; PASSIVE-PIC-NEXT: - Type: DATACOUNT +; PASSIVE-PIC-NEXT: Count: 1 +; PASSIVE-PIC-NEXT: - Type: CODE +; PASSIVE-PIC-NEXT: Functions: +; PASSIVE-PIC-NEXT: - Index: 0 +; PASSIVE-PIC-NEXT: Locals: [] +; PASSIVE-PIC-NEXT: Body: 10010B +; PASSIVE-PIC-NEXT: - Index: 1 +; PASSIVE-PIC-NEXT: Locals: [] +; PASSIVE-PIC-NEXT: Body: 0B +; PASSIVE-PIC-NEXT: - Index: 2 +; PASSIVE-PIC-NEXT: Locals: +; PASSIVE32-PIC-NEXT: - Type: I32 +; PASSIVE64-PIC-NEXT: - Type: I64 +; PASSIVE-PIC-NEXT: Count: 1 +; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B +; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B +; PASSIVE-PIC-NEXT: - Index: 3 +; PASSIVE-PIC-NEXT: Locals: [] +; PASSIVE-PIC-NEXT: Body: 0B +; PASSIVE-PIC-NEXT: - Type: DATA +; PASSIVE-PIC-NEXT: Segments: +; PASSIVE-PIC-NEXT: - SectionOffset: 4 +; PASSIVE-PIC-NEXT: InitFlags: 1 + +; PASSIVE-PIC: - Type: CUSTOM +; PASSIVE-PIC-NEXT: Name: name +; PASSIVE-PIC-NEXT: FunctionNames: +; PASSIVE-PIC-NEXT: - Index: 0 +; PASSIVE-PIC-NEXT: Name: __wasm_call_ctors +; PASSIVE-PIC-NEXT: - Index: 1 +; PASSIVE-PIC-NEXT: Name: __wasm_apply_relocs +; PASSIVE-PIC-NEXT: - Index: 2 +; PASSIVE-PIC-NEXT: Name: __wasm_init_memory +; PASSIVE-PIC-NEXT: - Index: 3 +; PASSIVE-PIC-NEXT: Name: __wasm_init_tls diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -869,10 +869,24 @@ LLVM_DEBUG(dbgs() << "createInitMemoryFunction\n"); assert(WasmSym::initMemoryFlag); uint64_t flagAddress = WasmSym::initMemoryFlag->getVirtualAddress(); + bool is64 = config->is64.getValueOr(false); std::string bodyContent; { raw_string_ostream os(bodyContent); - writeUleb128(os, 0, "num locals"); + // With PIC code we cache the flag address in local 0 + if (config->isPic) { + writeUleb128(os, 1, "num local decls"); + writeUleb128(os, 1, "local count"); + writeU8(os, is64 ? WASM_TYPE_I64 : WASM_TYPE_I32, "address type"); + writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); + writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base"); + writePtrConst(os, flagAddress, is64, "flag address"); + writeU8(os, WASM_OPCODE_I32_ADD, "add"); + writeU8(os, WASM_OPCODE_LOCAL_SET, "local.set"); + writeUleb128(os, 0, "local 0"); + } else { + writeUleb128(os, 0, "num locals"); + } if (hasPassiveInitializedSegments()) { // Initialize memory in a thread-safe manner. The thread that successfully @@ -916,11 +930,24 @@ // ) // ( ... drop data segments ... ) // ) + // + // When we are building with PIC, calculate the flag location using: + // + // (global.get $__memory_base) + // (i32.const $__init_memory_flag) + // (i32.const 1) - bool is64 = config->is64.getValueOr(false); + auto writeGetFlag = [&]() { + if (config->isPic) { + writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); + writeUleb128(os, 0, "local 0"); + } else { + writePtrConst(os, flagAddress, is64, "flag address"); + } + }; // Atomically check whether this is the main thread. - writePtrConst(os, flagAddress, is64, "flag address"); + writeGetFlag(); writeI32Const(os, 0, "expected flag value"); writeI32Const(os, 1, "flag value"); writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix"); @@ -930,7 +957,7 @@ writeU8(os, WASM_TYPE_NORESULT, "blocktype"); // Did not increment 0, so wait for main thread to initialize memory - writePtrConst(os, flagAddress, is64, "flag address"); + writeGetFlag(); writeI32Const(os, 1, "expected flag value"); writeI64Const(os, -1, "timeout"); @@ -946,6 +973,12 @@ if (needsPassiveInitialization(s)) { // destination address writePtrConst(os, s->startVA, is64, "destination address"); + if (config->isPic) { + writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); + writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), + "memory_base"); + writeU8(os, WASM_OPCODE_I32_ADD, "i32.add"); + } // source segment offset writeI32Const(os, 0, "segment offset"); // memory region size @@ -959,14 +992,14 @@ } // Set flag to 2 to mark end of initialization - writePtrConst(os, flagAddress, is64, "flag address"); + writeGetFlag(); writeI32Const(os, 2, "flag value"); writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix"); writeUleb128(os, WASM_OPCODE_I32_ATOMIC_STORE, "i32.atomic.store"); writeMemArg(os, 2, 0); // Notify any waiters that memory initialization is complete - writePtrConst(os, flagAddress, is64, "flag address"); + writeGetFlag(); writeI32Const(os, -1, "number of waiters"); writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix"); writeUleb128(os, WASM_OPCODE_ATOMIC_NOTIFY, "atomic.notify"); 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 @@ -263,6 +263,7 @@ WASM_OPCODE_END = 0x0b, WASM_OPCODE_CALL = 0x10, WASM_OPCODE_LOCAL_GET = 0x20, + WASM_OPCODE_LOCAL_SET = 0x21, WASM_OPCODE_GLOBAL_GET = 0x23, WASM_OPCODE_GLOBAL_SET = 0x24, WASM_OPCODE_I32_STORE = 0x36,