diff --git a/src/jsifier.mjs b/src/jsifier.mjs index 517f32de049da..d711dac771ba4 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -559,7 +559,7 @@ function(${args}) { // if the function was implemented in compiled code, there is no need to // include the js version - if (WASM_EXPORTS.has(symbol)) { + if (WASM_EXPORTS.has(symbol) && !WASM_IMPORTS.includes(symbol)) { return; } diff --git a/src/settings_internal.js b/src/settings_internal.js index e656c83fd455f..4adc2d495d478 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -16,6 +16,9 @@ // underscore. var WASM_EXPORTS = []; +// List of symbols imported from JavaScript +var WASM_IMPORTS = []; + // An array of all symbols exported from all the side modules specified on the // command line. // These are raw symbol names and are not mangled to include the leading diff --git a/test/test_other.py b/test/test_other.py index 7c38bfab2cad6..61c3c8b00dcef 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -1607,6 +1607,41 @@ def test_export_all(self): # Without the `-sEXPORT_ALL` these symbols will not be visible from JS self.do_runf('main.c', '_libf1 is not defined', assert_returncode=NON_ZERO, cflags=['-Oz', '-sMAIN_MODULE', '--pre-js', 'pre.js']) + def test_export_all_syscall_override(self): + create_file('main.c', r''' + #include "stdio.h" + #include + + int syscall_openat_orig(int dirfd, intptr_t path, int flags, void* varags) + __attribute__((__import_module__("env"), + __import_name__("__syscall_openat"), __warn_unused_result__)); + + int __syscall_openat(int dirfd, intptr_t path, int flags, void* varargs) { + printf("__syscall_openat!\n"); + return syscall_openat_orig(dirfd, path, flags, varargs); + } + + int main() { + int fd = open("a.c", O_RDONLY); + printf("fd: %d\n", fd); + } + ''') + + self.do_runf('main.c', '__syscall_openat!', cflags=['-sEXPORT_ALL', '-sNODERAWFS']) + self.do_runf('main.c', '__syscall_openat!', cflags=['-sMAIN_MODULE', '-sNODERAWFS']) + self.do_runf('main.c', '__syscall_openat!', cflags=['-O2', '-sEXPORT_ALL', '-sMAIN_MODULE', '-sNODERAWFS']) + self.do_runf('main.c', '__syscall_openat!', cflags=['-sEXPORT_ALL', '-sMAIN_MODULE', '-sNODERAWFS']) + + # Test with ES6 module output + self.run_process([EMCC, 'main.c', '-o', 'main.mjs', '-sEXPORT_ALL', '-sMAIN_MODULE', '-sNODERAWFS']) + create_file('run.mjs', ''' + import {default as loadModule} from './main.mjs' + + await loadModule(); + ''') + + self.assertContained('__syscall_openat!', self.run_js('run.mjs')) + def test_export_keepalive(self): create_file('main.c', r''' #include diff --git a/tools/emscripten.py b/tools/emscripten.py index 2f3a484a8b7c0..ca206fba8d678 100644 --- a/tools/emscripten.py +++ b/tools/emscripten.py @@ -114,8 +114,10 @@ def update_settings_glue(wasm_file, metadata, base_metadata): if base_metadata: settings.WASM_EXPORTS = base_metadata.all_exports + settings.WASM_IMPORTS = base_metadata.imports else: settings.WASM_EXPORTS = metadata.all_exports + settings.WASM_IMPORTS = metadata.imports settings.HAVE_EM_ASM = bool(settings.MAIN_MODULE or len(metadata.em_asm_consts) != 0) if settings.MAIN_MODULE and settings.ASYNCIFY == 1: @@ -969,7 +971,7 @@ def should_export(sym): return settings.EXPORT_ALL or (settings.EXPORT_KEEPALIVE and sym in settings.EXPORTED_FUNCTIONS) -def create_receiving(function_exports, other_exports, library_symbols, aliases): +def create_receiving(function_exports, other_exports, library_symbols, aliases, wasm_imports): generate_dyncall_assignment = 'dynCalls' in library_symbols receiving = ['\n// Imports from the Wasm binary.'] @@ -1019,6 +1021,7 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): # In debug builds we generate trapping functions in case # folks try to call/use a reference that was taken before the # wasm module is available. + wasm_imports_mangled = {asmjs_mangle(s) for s in wasm_imports} for sym in mangled: module_export = (settings.MODULARIZE or not settings.MINIMAL_RUNTIME) and should_export(sym) and settings.MODULARIZE != 'instance' if not js_manipulation.isidentifier(sym) and not module_export: @@ -1029,7 +1032,11 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): assignment += f" = Module['{sym}']" else: assignment = f"Module['{sym}']" - receiving.append(f"{assignment} = makeInvalidEarlyAccess('{sym}');") + # Don't generate early access traps for symbols that are also wasm imports. + if sym in wasm_imports_mangled: + receiving.append(f"{assignment};") + else: + receiving.append(f"{assignment} = makeInvalidEarlyAccess('{sym}');") else: # Declare all exports in a single var statement sep = ',\n ' @@ -1100,7 +1107,7 @@ def create_receiving(function_exports, other_exports, library_symbols, aliases): def create_module(metadata, function_exports, other_exports, library_symbols, aliases): module = [] - module.append(create_receiving(function_exports, other_exports, library_symbols, aliases)) + module.append(create_receiving(function_exports, other_exports, library_symbols, aliases, metadata.imports)) sending = create_sending(metadata, library_symbols) if settings.WASM_ESM_INTEGRATION: