[lld][WebAssembly] Fix --export-all when __stack_pointer is present
authorSam Clegg <sbc@chromium.org>
Tue, 15 Sep 2020 01:28:26 +0000 (18:28 -0700)
committerSam Clegg <sbc@chromium.org>
Tue, 15 Sep 2020 13:17:01 +0000 (06:17 -0700)
With https://reviews.llvm.org/D87537 we made it an error
to import or export a mutable global with the +mutable-globals
feature present.  However the scan was of the entire symbol
table rather than just the imports or exports and the filter
didn't match exaclyt meaning the `__stack_pointer` (a mutable
global) was always triggering with error when the `--export-all`
flag was used.

This also revealed that we didn't have any test coverage for
the `--export-all` flag.

This change fixes the current breakage on the emscripten-releases
roller.

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

lld/test/wasm/export-all.s [new file with mode: 0644]
lld/wasm/SyntheticSections.h
lld/wasm/Writer.cpp

diff --git a/lld/test/wasm/export-all.s b/lld/test/wasm/export-all.s
new file mode 100644 (file)
index 0000000..5f01381
--- /dev/null
@@ -0,0 +1,48 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
+# RUN: wasm-ld --export-all -o %t.wasm %t.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+.globl _start
+
+_start:
+  .functype _start () -> ()
+  i32.const 3
+  global.set __stack_pointer
+  end_function
+
+foo:
+  .functype foo () -> (i32)
+  i32.const 42
+  end_function
+
+.globaltype __stack_pointer, i32
+
+#      CHECK:   - Type:            EXPORT
+# CHECK-NEXT:     Exports:
+# CHECK-NEXT:       - Name:            memory
+# CHECK-NEXT:         Kind:            MEMORY
+# CHECK-NEXT:         Index:           0
+# CHECK-NEXT:       - Name:            __wasm_call_ctors
+# CHECK-NEXT:         Kind:            FUNCTION
+# CHECK-NEXT:         Index:           0
+# CHECK-NEXT:       - Name:            _start
+# CHECK-NEXT:         Kind:            FUNCTION
+# CHECK-NEXT:         Index:           1
+# CHECK-NEXT:       - Name:            __dso_handle
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           1
+# CHECK-NEXT:       - Name:            __data_end
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           2
+# CHECK-NEXT:       - Name:            __global_base
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           3
+# CHECK-NEXT:       - Name:            __heap_base
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           4
+# CHECK-NEXT:       - Name:            __memory_base
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           5
+# CHECK-NEXT:       - Name:            __table_base
+# CHECK-NEXT:         Kind:            GLOBAL
+# CHECK-NEXT:         Index:           6
index 3e125ca..335bfe8 100644 (file)
@@ -221,6 +221,7 @@ public:
   void writeBody() override;
 
   std::vector<llvm::wasm::WasmExport> exports;
+  std::vector<const Symbol *> exportedSymbols;
 };
 
 class StartSection : public SyntheticSection {
index 82b1aec..8d5b980 100644 (file)
@@ -463,26 +463,22 @@ void Writer::populateTargetFeatures() {
     return;
 
   if (!config->relocatable && used.count("mutable-globals") == 0) {
-    for (Symbol *sym : symtab->getSymbols()) {
+    for (const Symbol *sym : out.importSec->importedSymbols) {
       if (auto *global = dyn_cast<GlobalSymbol>(sym)) {
         if (global->getGlobalType()->Mutable) {
-          if (!sym->isLive())
-            continue;
-          if (!sym->isUsedInRegularObj)
-            continue;
-          if (sym->isUndefined() && sym->isWeak() && !config->relocatable)
-            continue;
-          if (sym->isUndefined())
-            error(Twine("mutable global imported but 'mutable-globals' feature "
-                        "not present in inputs: `") +
-                  toString(*sym) + "`. Use --no-check-features to suppress.");
-          else if (sym->isExported())
-            error(Twine("mutable global exported but 'mutable-globals' feature "
-                        "not present in inputs: `") +
-                  toString(*sym) + "`. Use --no-check-features to suppress.");
+          error(Twine("mutable global imported but 'mutable-globals' feature "
+                      "not present in inputs: `") +
+                toString(*sym) + "`. Use --no-check-features to suppress.");
         }
       }
     }
+    for (const Symbol *sym : out.exportSec->exportedSymbols) {
+      if (auto *global = dyn_cast<GlobalSymbol>(sym)) {
+        error(Twine("mutable global exported but 'mutable-globals' feature "
+                    "not present in inputs: `") +
+              toString(*sym) + "`. Use --no-check-features to suppress.");
+      }
+    }
   }
 
   if (config->sharedMemory) {
@@ -603,6 +599,7 @@ void Writer::calculateExports() {
 
     LLVM_DEBUG(dbgs() << "Export: " << name << "\n");
     out.exportSec->exports.push_back(export_);
+    out.exportSec->exportedSymbols.push_back(sym);
   }
 }
 
@@ -1075,8 +1072,6 @@ void Writer::run() {
   createSyntheticSections();
   log("-- populateProducers");
   populateProducers();
-  log("-- populateTargetFeatures");
-  populateTargetFeatures();
   log("-- calculateImports");
   calculateImports();
   log("-- layoutMemory");
@@ -1119,6 +1114,8 @@ void Writer::run() {
   calculateCustomSections();
   log("-- populateSymtab");
   populateSymtab();
+  log("-- populateTargetFeatures");
+  populateTargetFeatures();
   log("-- addSections");
   addSections();