Iain Duncan
Iain Duncan

Reputation: 1772

How to compile and use malloc in a standalone WASM C module

I've been pulling out my hair and am hoping someone can help as I have been unable to find an example of what I need to do and am in link error hell. :-)

I'm trying to get a C module working, with which I can share memory and call back into JS. The tricky bit is this is going into an AudioWorklet, so I cannot just compile to js and get the module plumbing from emscripten. In order to load it, I must manually instantiate. Binary data is fetched in the main file, sent to the worklet as a message, and then compiled and instantiated there. This is working fine when I compile as a side module, and I can access my dummy C function (multiply) ok. compile line is:

emcc multiply.c -O2 -s WASM=1 -s SIDE_MODULE=2 -s EXPORTED_FUNCTIONS=['_multiply'] -o multiply.wasm

Instantiation in the worklet looks like this:

    console.log("initWasm()");
    // setup linear memory for the WASM module
    const importObject = {
      'env': {
        __memory_base: 0,
        __table_base: 0,
        memory: new WebAssembly.Memory({initial: 10}),
        table: new WebAssembly.Table({initial: 0, element: 'anyfunc'})
      }
    }
    this.module = await WebAssembly.compile(data.arrayBuffer);
    this.instance = await WebAssembly.instantiate(this.module, importObject);

All good so far. But attempting to write memory such that C can access is it where I'm stuck. I have found this example (adapted a bit)

var buf = Module._malloc(this._events.length * this._events.BYTES_PER_ELEMENT);
Module.module.HEAPU8.set(this._events, buf);

But of course I don't have "Module" because it was a manual instantiation of a side module. So I tried various variants on:

emcc multiply.c -O2 -s WASM=1 -s SIDE_MODULE=2 -s EXPORTED_FUNCTIONS=['_malloc','_multiply'] -s EXPORTED_RUNTIME_METHODS=['cwrap','ccall','UTF8ToString'] -o multiply.wasm

With this in my js

var buf = this.module._malloc(this._events.length * this._events.BYTES_PER_ELEMENT);
this.module.HEAPU8.set(this._events, buf);

But I am not getting a malloc. I tried adding this to init above to check on it, but there is no malloc.

console.log(" this.module._malloc:", this.module._malloc);
console.log(" this.module.malloc:", this.module.malloc);
console.log(" this.instance.exports._malloc:", this.instance.exports._malloc);
console.log(" this.instance.exports.malloc:", this.instance.exports.malloc);

My C file looks like this:

#include <stdlib.h>
#include <stdio.h>
include "emscripten.h"

EMSCRIPTEN_KEEPALIVE 
// a function to compile as wasm 
float multiply(float arg1, float arg2){ return arg1 * arg2; }

If anyone knows how to get this to work, that would be lovely. Or any suggestions on how to figure it out.

thanks!

Upvotes: 0

Views: 1180

Answers (1)

sbc100
sbc100

Reputation: 3022

You want to be using the STANDALONE_WASM mode, not SIDE_MODULE. See https://v8.dev/blog/emscripten-standalone-wasm.

Standalone mode can be enabled either explictly via -sSTANDALONE_WASM or implicitly by specifying an output name that ends in .wasm. e.g. emcc hello.c -o hello.wasm.

Upvotes: 1

Related Questions