Skip to content

LibraryImport fails to resolve side modules on browser-wasm #123570

@denis-kudelin

Description

@denis-kudelin

Description

LibraryImport on browser-wasm fails to resolve symbols from Emscripten side modules even when the module exists in the app bundle and dlopen would succeed. This scenario requires Emscripten dynamic linking (-s MAIN_MODULE=1 / -s SIDE_MODULE=1), which the .NET SDK does not enable by default, but the runtime should still resolve symbols correctly when it is used. Today the runtime only checks the generated pinvoke table and does not attempt dlopen for non-table names, so side modules cannot be resolved.

Reproduction Steps

  1. Build a browser-wasm app with Emscripten main module support:
    • Link flags: -s MAIN_MODULE=1
  2. Build a side module with one exported function:
    • emcc -O0 -s SIDE_MODULE=1 -s EXPORT_ALL=1 -o libmylib.wasm side-module.c
    • side-module.c:
      int side_add(int a, int b) { return a + b; }
      
  3. Ensure the side module is included in the app bundle (e.g., WasmNativeAsset with TargetPath = libmylib.wasm so it exists in the virtual FS).
  4. Use LibraryImport in managed code (note: no extension in the name to exercise suffix probing):
    [LibraryImport("libmylib", EntryPoint = "side_add")]
    internal static partial int SideAdd(int a, int b);
    
  5. Run the app.

Expected behavior

LibraryImport resolves side_add from libmylib.wasm and returns correct results. Names without an explicit extension should be probed with the platform suffix (WASM: .wasm), so libmylib and libmylib.wasm are equivalent.

Actual behavior

LibraryImport fails with DllNotFoundException or EntryPointNotFoundException, despite the side module being present and dlopen being able to load it. The runtime never attempts dlopen for non-table names.

Known Workarounds

Link native code into the main module (no side module) so the symbol is present in the generated pinvoke table.

Configuration

  • .NET version: main (net11.0).
  • Runtime: Mono browser-wasm.
  • Build flags: WasmBuildNative=true, -s MAIN_MODULE=1 (main module), -s SIDE_MODULE=1 -s EXPORT_ALL=1 (side module).

Other information

Runtime currently prioritizes pinvoke table lookups and does not fall back to dlopen for non-table names. For dynamic linking, it should attempt dlopen(name) after the pinvoke table check and rely on the platform suffix probing (WASM: .wasm).

Metadata

Metadata

Assignees

Type

No type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions