diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -872,7 +872,20 @@ 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, WASM_TYPE_I32, "address type"); + writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); + writeUleb128(os, WasmSym::memoryBase->getGlobalIndex(), "memory_base"); + writeI32Const(os, flagAddress, "flag address"); + writeU8(os, WASM_OPCODE_I32_ADD, "i32.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,9 +929,21 @@ // ) // ( ... drop data segments ... ) // ) + // + // In the case we are building with PIC the calculate the + // flag location using: + // + // (global.get $__memory_base) + // (i32.const $__init_memory_flag) + // (i32.const 1) // Atomically check whether this is the main thread. - writeI32Const(os, flagAddress, "flag address"); + if (config->isPic) { + writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); + writeUleb128(os, 0, "local 0"); + } else { + writeI32Const(os, flagAddress, "flag address"); + } writeI32Const(os, 0, "expected flag value"); writeI32Const(os, 1, "flag value"); writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix"); @@ -928,7 +953,12 @@ writeU8(os, WASM_TYPE_NORESULT, "blocktype"); // Did not increment 0, so wait for main thread to initialize memory - writeI32Const(os, flagAddress, "flag address"); + if (config->isPic) { + writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); + writeUleb128(os, 0, "local 0"); + } else { + writeI32Const(os, flagAddress, "flag address"); + } writeI32Const(os, 1, "expected flag value"); writeI64Const(os, -1, "timeout"); writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix"); @@ -948,6 +978,12 @@ writeI32Const(os, static_cast(s->startVA), "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 @@ -961,14 +997,24 @@ } // Set flag to 2 to mark end of initialization - writeI32Const(os, flagAddress, "flag address"); + if (config->isPic) { + writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); + writeUleb128(os, 0, "local 0"); + } else { + writeI32Const(os, flagAddress, "flag address"); + } 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 - writeI32Const(os, flagAddress, "flag address"); + if (config->isPic) { + writeU8(os, WASM_OPCODE_LOCAL_GET, "local.get"); + writeUleb128(os, 0, "local 0"); + } else { + writeI32Const(os, flagAddress, "flag address"); + } 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,