WebAssembly / WebAssembly/binaryen

Dynamic Linking with emscripten.

Open
#1,955 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
WebAssembly
Stars
8.6k
Forks
885
Avg merge
1d 19h
Merged PRs (30d)
69

Description

Hi,

I have been trying to experiment with dynamic linking of wasm modules i.e. module 1 would export func foo, and module 2 would import foo.

I have primarily referred to https://webassembly.org/docs/dynamic-linking/ and https://github.com/emscripten-core/emscripten/wiki/Linking.

My code is,
square.c

#include <emscripten.h>
#  define EXPORT __attribute__ ((visibility ("default")))
EXPORT EMSCRIPTEN_KEEPALIVE
int square(int x) {	
  return x * x;
}

cube.c

#  define EXPORT __attribute__ ((visibility ("default")))
#  define IMPORT __attribute__ ((visibility ("default")))
typedef int (**PF)(int);
IMPORT PF square();
EXPORT int cube(int x) { return (*square())(x) * x; }

The emcc commands used are,
emcc square.c -Os -s WASM=1 -s -s SIDE_MODULE=1 -s EXPORTED_FUNCTIONS='["_square"]' -o square.wasm
emcc cube.c -Os -s WASM=1 -s SIDE_MODULE=1 -s EXPORTED_FUNCTIONS='["_cube"]' -o cube.wasm

The JS to load the module is based on https://gist.github.com/kripken/59c67556dc03bb6d57052fedef1e61ab

  <script>
    // Check for wasm support.
    if (!('WebAssembly' in window)) {
      alert('you need a browser with wasm support enabled :(');
    }
    // Loads a WebAssembly dynamic library, returns a promise.
    // imports is an optional imports object
    function loadWebAssembly(filename, imports) {
      // Fetch the file and compile it
      return fetch(filename)
        .then(response => response.arrayBuffer())
        .then(buffer => WebAssembly.compile(buffer))
        .then(module => {
          // Create the imports for the module, including the
          // standard dynamic library imports
          imports = imports || {};
          imports.env = imports.env || {};
          imports.env.__memory_base = imports.env.__memory_base || 0;
          imports.env.__table_base = imports.env.__table_base || 0;
          if (!imports.env.memory) {
            imports.env.memory = new WebAssembly.Memory({ initial: 256 });
          }
          if (!imports.env.table) {
            imports.env.table = new WebAssembly.Table({ initial: 0, element: 'anyfunc' });
          }
          // Create the instance.
          return new WebAssembly.Instance(module, imports);
        });
    }

    loadWebAssembly('square.wasm')
      .then(instance => {
        var exports = instance.exports; 
        var square = exports._square; 
       
        var button = document.getElementById('run');
        button.value = 'Call a method in the WebAssembly module';
        button.addEventListener('click', function() {
          var input = 21;
          alert(input + ' square is ' + square(input));
        }, false);
      }
    );
    
    loadWebAssembly('cube.wasm')
      .then(instance => {
        var exports = instance.exports;
        var cube = exports._cube; 
      
        var button = document.getElementById('run');
        button.value = 'Call a method in the WebAssembly module';
        button.addEventListener('click', function() {
          var input = 21;
          alert(input + ' cube is ' + cube(input));
        }, false);
      }
    );   
  </script>

But i get error in cube.wasm instantiation as,
Uncaught (in promise) LinkError: WebAssembly Instantiation: Import #0 module="env" function="abort" error: function import requires a callable

If I change cube.wasm compile command to have the flag, -s ONLY_MY_CODE=1, then the exported function is not found.
Uncaught (in promise) LinkError: WebAssembly Instantiation: Import #0 module="env" function="_square" error: function import requires a callable

Can anyone help me. Where i am going wrong ?

Thanks.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with square.c, cube.c, the two emcc commands, and the loadWebAssembly script; compare them with the WebAssembly dynamic-linking and Emscripten Linking references included in the issue. Reproduce the abort and _square import errors, then verify that both modules instantiate and cube can call square.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, wasm
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.