Skip to content

Commit d9a2c46

Browse files
sbc100memfrob
authored and
memfrob
committed
[lld][WebAssembly] Allow exporting of mutable globals
In particular allow explict exporting of `__stack_pointer` but exclud this from `--export-all` to avoid requiring the mutable globals feature whenenve `--export-all` is used. This uncovered a bug in populateTargetFeatures regarding checking if the mutable-globals feature is allowed. See: WebAssembly/binaryen#2934 Differential Revision: https://reviews.llvm.org/D88506
1 parent 7f37d41 commit d9a2c46

File tree

4 files changed

+101
-7
lines changed

4 files changed

+101
-7
lines changed

lld/docs/WebAssembly.rst

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ WebAssembly-specific options:
3939

4040
Export all symbols (normally combined with --no-gc-sections)
4141

42+
Note that this will not export linker-generated mutable globals unless
43+
the resulting binaryen already includes the 'mutable-globals' features
44+
since that would otherwise create and invalid binaryen.
45+
4246
.. option:: --export-dynamic
4347

4448
When building an executable, export any non-hidden symbols. By default only
+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
2+
#
3+
# Should fail without mutable globals feature enabled.
4+
# RUN: not wasm-ld --export-all %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-ERR %s
5+
# RUN: not wasm-ld --export=foo_global %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-ERR %s
6+
#
7+
# RUN: wasm-ld --features=mutable-globals --export=foo_global %t.o -o %t.wasm
8+
# RUN: obj2yaml %t.wasm | FileCheck %s
9+
10+
# Explcitly check that __stack_pointer can be exported
11+
# RUN: wasm-ld --features=mutable-globals --export=__stack_pointer %t.o -o %t.wasm
12+
# RUN: obj2yaml %t.wasm | FileCheck -check-prefix=CHECK-SP %s
13+
14+
# RUN: wasm-ld --features=mutable-globals --export-all %t.o -o %t.wasm
15+
# RUN: obj2yaml %t.wasm | FileCheck -check-prefix=CHECK-ALL %s
16+
17+
18+
.globl _start
19+
.globl foo_global
20+
21+
.globaltype foo_global, i32
22+
foo_global:
23+
24+
_start:
25+
.functype _start () -> ()
26+
end_function
27+
28+
# CHECK-ERR: mutable global exported but 'mutable-globals' feature not present in inputs: `foo_global`. Use --no-check-features to suppress
29+
30+
# CHECK: - Type: EXPORT
31+
# CHECK-NEXT: Exports:
32+
# CHECK-NEXT: - Name: memory
33+
# CHECK-NEXT: Kind: MEMORY
34+
# CHECK-NEXT: Index: 0
35+
# CHECK-NEXT: - Name: _start
36+
# CHECK-NEXT: Kind: FUNCTION
37+
# CHECK-NEXT: Index: 0
38+
# CHECK-NEXT: - Name: foo_global
39+
# CHECK-NEXT: Kind: GLOBAL
40+
# CHECK-NEXT: Index: 1
41+
# CHECK-NEXT: - Type: CODE
42+
43+
# CHECK-SP: - Type: EXPORT
44+
# CHECK-SP-NEXT: Exports:
45+
# CHECK-SP-NEXT: - Name: memory
46+
# CHECK-SP-NEXT: Kind: MEMORY
47+
# CHECK-SP-NEXT: Index: 0
48+
# CHECK-SP-NEXT: - Name: __stack_pointer
49+
# CHECK-SP-NEXT: Kind: GLOBAL
50+
# CHECK-SP-NEXT: Index: 0
51+
# CHECK-SP-NEXT: - Name: _start
52+
# CHECK-SP-NEXT: Kind: FUNCTION
53+
# CHECK-SP-NEXT: Index: 0
54+
# CHECK-SP-NEXT: - Type: CODE
55+
56+
# CHECK-ALL: - Type: EXPORT
57+
# CHECK-ALL-NEXT: Exports:
58+
# CHECK-ALL-NEXT: - Name: memory
59+
# CHECK-ALL-NEXT: Kind: MEMORY
60+
# CHECK-ALL-NEXT: Index: 0
61+
# CHECK-ALL-NEXT: - Name: __wasm_call_ctors
62+
# CHECK-ALL-NEXT: Kind: FUNCTION
63+
# CHECK-ALL-NEXT: Index: 0
64+
# CHECK-ALL-NEXT: - Name: _start
65+
# CHECK-ALL-NEXT: Kind: FUNCTION
66+
# CHECK-ALL-NEXT: Index: 1
67+
# CHECK-ALL-NEXT: - Name: foo_global
68+
# CHECK-ALL-NEXT: Kind: GLOBAL
69+
# CHECK-ALL-NEXT: Index: 1
70+
# CHECK-ALL-NEXT: - Name: __dso_handle
71+
# CHECK-ALL-NEXT: Kind: GLOBAL
72+
# CHECK-ALL-NEXT: Index: 2
73+
# CHECK-ALL-NEXT: - Name: __data_end
74+
# CHECK-ALL-NEXT: Kind: GLOBAL
75+
# CHECK-ALL-NEXT: Index: 3
76+
# CHECK-ALL-NEXT: - Name: __global_base
77+
# CHECK-ALL-NEXT: Kind: GLOBAL
78+
# CHECK-ALL-NEXT: Index: 4
79+
# CHECK-ALL-NEXT: - Name: __heap_base
80+
# CHECK-ALL-NEXT: Kind: GLOBAL
81+
# CHECK-ALL-NEXT: Index: 5
82+
# CHECK-ALL-NEXT: - Name: __memory_base
83+
# CHECK-ALL-NEXT: Kind: GLOBAL
84+
# CHECK-ALL-NEXT: Index: 6
85+
# CHECK-ALL-NEXT: - Name: __table_base
86+
# CHECK-ALL-NEXT: Kind: GLOBAL
87+
# CHECK-ALL-NEXT: Index: 7
88+
# CHECK-ALL-NEXT: - Type: CODE

lld/test/wasm/mutable-globals.s

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
22
# RUN: not wasm-ld %t.o -o %t.wasm 2>&1 | FileCheck %s
3+
# RUN: wasm-ld --features=mutable-globals %t.o -o %t.wasm
34

45
.globl _start
56
_start:

lld/wasm/Writer.cpp

+8-7
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ void Writer::populateTargetFeatures() {
453453
if (!config->checkFeatures)
454454
return;
455455

456-
if (!config->relocatable && used.count("mutable-globals") == 0) {
456+
if (!config->relocatable && allowed.count("mutable-globals") == 0) {
457457
for (const Symbol *sym : out.importSec->importedSymbols) {
458458
if (auto *global = dyn_cast<GlobalSymbol>(sym)) {
459459
if (global->getGlobalType()->Mutable) {
@@ -571,12 +571,13 @@ void Writer::calculateExports() {
571571
}
572572
export_ = {name, WASM_EXTERNAL_FUNCTION, f->getFunctionIndex()};
573573
} else if (auto *g = dyn_cast<DefinedGlobal>(sym)) {
574-
// TODO(sbc): Remove this check once to mutable global proposal is
575-
// implement in all major browsers.
576-
// See: https://github.com/WebAssembly/mutable-global
577-
if (g->getGlobalType()->Mutable) {
578-
// Only __stack_pointer and __tls_base should ever be create as mutable.
579-
assert(g == WasmSym::stackPointer || g == WasmSym::tlsBase);
574+
if (g->getGlobalType()->Mutable && !g->getFile() && !g->forceExport) {
575+
// Avoid exporting mutable globals are linker synthesized (e.g.
576+
// __stack_pointer or __tls_base) unless they are explicitly exported
577+
// from the command line.
578+
// Without this check `--export-all` would cause any program using the
579+
// stack pointer to export a mutable global even if none of the input
580+
// files were built with the `mutable-globals` feature.
580581
continue;
581582
}
582583
export_ = {name, WASM_EXTERNAL_GLOBAL, g->getGlobalIndex()};

0 commit comments

Comments
 (0)