[lld][WebAssembly] Set memory limits correctly for PIC + shared memory
authorSam Clegg <sbc@chromium.org>
Thu, 3 Dec 2020 01:14:57 +0000 (17:14 -0800)
committerSam Clegg <sbc@chromium.org>
Fri, 4 Dec 2020 02:14:28 +0000 (18:14 -0800)
Don't early return from layoutMemory in PIC mode before we have set the
memory limits.

This matters in particular with shared-memory + PIC because shared
memories require maximum size.

Secondly, when we need a maximum, but the user does not supply one,
default to MAX_INT rather than 0 (defaulting to zero is completely
useless and means that building with -shared didn't previously work at
all without --maximum-memory, because zero is never big enough).

This is part of an ongoing effort to enable dynamic linking with
threads in emscripten.

See https://github.com/emscripten-core/emscripten/issues/3494

Differential Revision: https://reviews.llvm.org/D92528

lld/test/wasm/shared-memory.yaml
lld/test/wasm/shared.ll
lld/wasm/Writer.cpp

index 11dd6b1..8710a06 100644 (file)
@@ -1,6 +1,6 @@
 # RUN: yaml2obj %s -o %t1.o
 
-# RUN: not wasm-ld --no-entry --shared-memory %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-NO-MAX
+# RUN: wasm-ld --no-entry --shared-memory --features=atomics,bulk-memory %t1.o -o - | obj2yaml | FileCheck %s --check-prefix SHARED
 
 # RUN: not wasm-ld --no-entry --shared-memory --max-memory=100000 %t1.o -o - 2>&1 | FileCheck %s --check-prefix SHARED-UNALIGNED
 
@@ -56,8 +56,6 @@ Sections:
         Flags:           [  ]
 ...
 
-# SHARED-NO-MAX: maximum memory too small, 66576 bytes needed{{$}}
-
 # SHARED-UNALIGNED: maximum memory must be 65536-byte aligned{{$}}
 
 # SHARED-NO-ATOMICS: 'atomics' feature must be used in order to use shared memory
index 3740ea3..98751ad 100644 (file)
@@ -1,5 +1,5 @@
 ; RUN: llc -relocation-model=pic -mattr=+mutable-globals -filetype=obj %s -o %t.o
-; RUN: wasm-ld -shared -o %t.wasm %t.o
+; RUN: wasm-ld --experimental-pic -shared -o %t.wasm %t.o
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 
 target triple = "wasm32-unknown-emscripten"
@@ -67,7 +67,7 @@ declare void @func_external()
 ; CHECK-NEXT:         Field:           memory
 ; CHECK-NEXT:         Kind:            MEMORY
 ; CHECK-NEXT:         Memory:
-; CHECK-NEXT:           Initial:       0x0
+; CHECK-NEXT:           Initial:       0x1
 ; CHECK-NEXT:       - Module:          env
 ; CHECK-NEXT:         Field:           __indirect_function_table
 ; CHECK-NEXT:         Kind:            TABLE
index 89f79ae..d927b71 100644 (file)
@@ -308,20 +308,19 @@ void Writer::layoutMemory() {
 
   uint64_t staticDataSize = memoryPtr - dataStart;
   log("mem: static data = " + Twine(staticDataSize));
-  if (config->isPic) {
+  if (config->isPic)
     out.dylinkSec->memSize = staticDataSize;
-    return;
-  }
 
   if (!config->stackFirst)
     placeStack();
 
-  // Set `__heap_base` to directly follow the end of the stack or global data.
-  // The fact that this comes last means that a malloc/brk implementation
-  // can grow the heap at runtime.
-  log("mem: heap base   = " + Twine(memoryPtr));
-  if (WasmSym::heapBase)
+  if (WasmSym::heapBase) {
+    // Set `__heap_base` to directly follow the end of the stack or global data.
+    // The fact that this comes last means that a malloc/brk implementation
+    // can grow the heap at runtime.
+    log("mem: heap base   = " + Twine(memoryPtr));
     WasmSym::heapBase->setVirtualAddress(memoryPtr);
+  }
 
   uint64_t maxMemorySetting = 1ULL
                               << (config->is64.getValueOr(false) ? 48 : 32);
@@ -340,8 +339,7 @@ void Writer::layoutMemory() {
       alignTo(memoryPtr, WasmPageSize) / WasmPageSize;
   log("mem: total pages = " + Twine(out.memorySec->numMemoryPages));
 
-  // Check max if explicitly supplied or required by shared memory
-  if (config->maxMemory != 0 || config->sharedMemory) {
+  if (config->maxMemory != 0) {
     if (config->maxMemory != alignTo(config->maxMemory, WasmPageSize))
       error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned");
     if (memoryPtr > config->maxMemory)
@@ -349,7 +347,20 @@ void Writer::layoutMemory() {
     if (config->maxMemory > maxMemorySetting)
       error("maximum memory too large, cannot be greater than " +
             Twine(maxMemorySetting));
-    out.memorySec->maxMemoryPages = config->maxMemory / WasmPageSize;
+  }
+
+  // Check max if explicitly supplied or required by shared memory
+  if (config->maxMemory != 0 || config->sharedMemory) {
+    uint64_t max = config->maxMemory;
+    if (max == 0) {
+      // If no maxMemory config was supplied but we are building with
+      // shared memory, we need to pick a sensible upper limit.
+      if (config->isPic)
+        max = maxMemorySetting;
+      else
+        max = alignTo(memoryPtr, WasmPageSize);
+    }
+    out.memorySec->maxMemoryPages = max / WasmPageSize;
     log("mem: max pages   = " + Twine(out.memorySec->maxMemoryPages));
   }
 }