Skip to content

Commit 8817d7f

Browse files
committed
Read exports from side modules at link time
This means we can reason about the symbols which are or are not defined across the entire program which allows for ERROR_ON_UNDEFINED_SYMBOLS to be enabled for any build that includes all its side modules on the command line.
1 parent a543758 commit 8817d7f

13 files changed

+81
-14
lines changed

emcc.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -631,13 +631,17 @@ def process_dynamic_libs(dylibs):
631631
imports = webassembly.get_imports(dylib)
632632
new_exports = []
633633
for imp in imports:
634-
if imp.type not in (webassembly.ExternType.FUNC, webassembly.ExternType.GLOBAL):
634+
if imp.kind not in (webassembly.ExternType.FUNC, webassembly.ExternType.GLOBAL):
635635
continue
636636
new_exports.append(imp.field)
637637
logger.debug('Adding exports based on `%s`: %s', dylib, new_exports)
638638
shared.Settings.EXPORTED_FUNCTIONS.extend(shared.asmjs_mangle(e) for e in new_exports)
639639
shared.Settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.extend(new_exports)
640640

641+
exports = webassembly.get_exports(dylib)
642+
for export in exports:
643+
shared.Settings.SIDE_MODULE_SYMBOLS.append(shared.asmjs_mangle(export.name))
644+
641645

642646
def unmangle_symbols_from_cmdline(symbols):
643647
def unmangle(x):
@@ -1447,9 +1451,13 @@ def default_setting(name, new_default):
14471451
'__heap_base',
14481452
'__stack_pointer',
14491453
]
1450-
# This needs to be exported on the Module object too so it's visible
1451-
# to side modules too.
1452-
shared.Settings.EXPORTED_FUNCTIONS += ['___heap_base']
1454+
shared.Settings.EXPORTED_FUNCTIONS += [
1455+
# This needs to be exported on the Module object too so it's visible
1456+
# to side modules too.
1457+
'___heap_base',
1458+
# Unconditional dependency in library_dylink.js
1459+
'_setThrew',
1460+
]
14531461
if shared.Settings.MINIMAL_RUNTIME:
14541462
exit_with_error('MINIMAL_RUNTIME is not compatible with relocatable output')
14551463
if shared.Settings.WASM2JS:

src/compiler.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ if (settingsFile) {
6767
EXPORTED_FUNCTIONS = set(EXPORTED_FUNCTIONS);
6868
EXCEPTION_CATCHING_ALLOWED = set(EXCEPTION_CATCHING_ALLOWED);
6969
IMPLEMENTED_FUNCTIONS = set(IMPLEMENTED_FUNCTIONS);
70+
SIDE_MODULE_SYMBOLS = set(SIDE_MODULE_SYMBOLS);
7071
INCOMING_MODULE_JS_API = set(INCOMING_MODULE_JS_API);
7172

7273
RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;

src/jsifier.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ function stringifyWithFunctions(obj) {
4949
}
5050
}
5151

52+
function isDefined(symName) {
53+
if (symName in IMPLEMENTED_FUNCTIONS || symName in SIDE_MODULE_SYMBOLS) {
54+
return true;
55+
}
56+
// 'invoke_' symbols are created at runtime in libary_dylink.py so can
57+
// always be considered as defined.
58+
if (RELOCATABLE && symName.startsWith('_invoke_')) {
59+
return true;
60+
}
61+
return false;
62+
}
63+
5264
// JSifier
5365
function JSify(functionsOnly) {
5466
var mainPass = !functionsOnly;
@@ -147,7 +159,7 @@ function JSify(functionsOnly) {
147159
var noExport = false;
148160

149161
if (!LibraryManager.library.hasOwnProperty(ident)) {
150-
if (!(finalName in IMPLEMENTED_FUNCTIONS) && !LINKABLE) {
162+
if (!isDefined(finalName) && !LINKABLE) {
151163
var msg = 'undefined symbol: ' + ident;
152164
if (dependent) msg += ' (referenced by ' + dependent + ')';
153165
if (ERROR_ON_UNDEFINED_SYMBOLS) {

src/library.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ LibraryManager.library = {
3535
{{{ makeSetTempRet0('$i') }}};
3636
},
3737

38+
#if SAFE_HEAP
39+
// Trivial wrappers around runtime functions that make these symbols available
40+
// to native code.
41+
segfault: function() { segfault(); },
42+
alignfault: function() { alignfault(); },
43+
ftfault: function() { ftfault(); },
44+
#endif
45+
3846
// ==========================================================================
3947
// JavaScript <-> C string interop
4048
// ==========================================================================

src/modules.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,14 @@ function exportRuntime() {
443443
'abort',
444444
];
445445

446+
if (SAFE_HEAP) {
447+
runtimeElements = runtimeElements.concat([
448+
'segfault',
449+
'ftfault',
450+
'alignfault',
451+
])
452+
}
453+
446454
if (USE_OFFSET_CONVERTER) {
447455
runtimeElements.push('WasmOffsetConverter');
448456
}

src/settings_internal.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,5 @@ var HEAP_BASE = 0;
193193
// Also set for STANDALONE_WASM since the _start function is needed to call
194194
// static ctors, even if there is no user main.
195195
var HAS_MAIN = 0;
196+
197+
var SIDE_MODULE_SYMBOLS = [];

tests/other/metadce/hello_world_O3_MAIN_MODULE_2.exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ __wasm_call_ctors
22
dynCall_jiji
33
main
44
malloc
5+
setThrew
56
stackAlloc
67
stackRestore
78
stackSave

tests/other/metadce/hello_world_O3_MAIN_MODULE_2.funcs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ $dlmalloc
99
$legalstub$dynCall_jiji
1010
$main
1111
$sbrk
12+
$setThrew
1213
$stackAlloc
1314
$stackRestore
1415
$stackSave
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
wrote profile of 236 bytes (allocated 236 bytes)
1+
wrote profile of 240 bytes (allocated 240 bytes)
22
Hello from main!
33
Hello from lib!

tests/test_core.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,6 +3594,7 @@ def dylink_testf(self, main, side, expected=None, force_c=False, main_emcc_args=
35943594

35953595
# side settings
35963596
self.clear_setting('MAIN_MODULE')
3597+
self.clear_setting('ERROR_ON_UNDEFINED_SYMBOLS')
35973598
self.set_setting('SIDE_MODULE')
35983599
side_suffix = 'wasm' if self.is_wasm() else 'js'
35993600
if isinstance(side, list):
@@ -3608,10 +3609,14 @@ def dylink_testf(self, main, side, expected=None, force_c=False, main_emcc_args=
36083609
self.set_setting('MAIN_MODULE', main_module)
36093610
self.clear_setting('SIDE_MODULE')
36103611
if auto_load:
3612+
# Normally we don't report undefined symbols when linking main modules but
3613+
# in this case we know all the side modules are specified on the command line.
3614+
# TODO(sbc): Make this the default one day
3615+
self.set_setting('ERROR_ON_UNDEFINED_SYMBOLS')
36113616
self.emcc_args += main_emcc_args
36123617
self.emcc_args.append('liblib.so')
3613-
if force_c:
3614-
self.emcc_args.append('-nostdlib++')
3618+
if force_c:
3619+
self.emcc_args.append('-nostdlib++')
36153620

36163621
if isinstance(main, list):
36173622
# main is just a library

0 commit comments

Comments
 (0)