; 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
; 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
; 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
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
// )
// ( ... 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 writeGetFlagAddress = [&]() {
+ 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");
+ writeGetFlagAddress();
writeI32Const(os, 0, "expected flag value");
writeI32Const(os, 1, "flag value");
writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix");
writeU8(os, WASM_TYPE_NORESULT, "blocktype");
// Did not increment 0, so wait for main thread to initialize memory
- writePtrConst(os, flagAddress, is64, "flag address");
+ writeGetFlagAddress();
writeI32Const(os, 1, "expected flag value");
writeI64Const(os, -1, "timeout");
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
}
// Set flag to 2 to mark end of initialization
- writePtrConst(os, flagAddress, is64, "flag address");
+ writeGetFlagAddress();
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");
+ writeGetFlagAddress();
writeI32Const(os, -1, "number of waiters");
writeU8(os, WASM_OPCODE_ATOMICS_PREFIX, "atomics prefix");
writeUleb128(os, WASM_OPCODE_ATOMIC_NOTIFY, "atomic.notify");
}
void Writer::createInitTLSFunction() {
- if (!WasmSym::initTLS->isLive())
- return;
-
std::string bodyContent;
{
raw_string_ostream os(bodyContent);
}
}
- if (!config->relocatable && config->sharedMemory && !config->shared)
+ if (WasmSym::initTLS && WasmSym::initTLS->isLive())
createInitTLSFunction();
if (errorCount())