binaryen icon indicating copy to clipboard operation
binaryen copied to clipboard

Uncaught WasmModule::Instantiate(): Import #0 module="env" function="abort" error: FFI is not an object

Open tsangint opened this issue 7 years ago • 15 comments

I use emscripten and binaryen to compiled c/c++ to wasm file.

//get wast file
emcc hello.c -s "BINARYEN='/home/vagrant/emscripten/binaryen/'" -s "BINARYEN_METHOD='native-wasm'"

//get wasm file
wasm-as a.out.wast -o a.out.wasm
var xhr = new XMLHttpRequest();
xhr.open('GET', 'a.out.wasm', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
    myWasm = Wasm.instantiateModule(xhr.response);
}
xhr.send(null);

Then there is a error in my console.

But when I replace a.out.wasm to http://blog.mikaellundin.name/assets/posts/2016-06-19-creating-a-webassembly-binary-and-running-it-in-a-browser/out.wasm(a wasm file compile by other people), It's ok. Is there anything wrong when I compile to wasm?

tsangint avatar Aug 14 '16 02:08 tsangint

Those commands look ok. What is the error you see in the console?

kripken avatar Aug 15 '16 17:08 kripken

I am getting the same error.

Full code

Latest emscripten, chrome canary.

bodokaiser avatar Nov 12 '16 16:11 bodokaiser

Oh, is the error you see in the console what's in the title? "Import #0 module="env" function="abort" error: FFI is not an object"? I missed it the first time I read this.

Then the error is that the module is trying to import env.abort. But when you instantiate the module, you don't provide any imports.

By default emcc will generate a .js file that will instantiate the wasm module and pass it the necessary imports automatically for you.

Instead, if you want to instantiate it yourself, you can look in the .wast at what it expects. However, you'll need to match the ABI expectations as well, like creating the stack, libc syscall imports if you print etc. In other words, emcc emits wasm files that are not standalone, they are designed to work with the .js file emcc emits for you.

In theory a wasm file could be standalone, if you don't use any imports, manage your own stack, etc. and just provide exports that are called from outside. You can try to experiment with this using the ONLY_MY_CODE option to emcc, but it's not much tested yet - the main focus in emscripten has been to get C and C++ programs to "just work". Doing that requires some JS, e.g., to print output, to receive input, to handle a virtual filesystem, to render to canvas, etc. But it would be good to improve support for standalone wasm files using ONLY_MY_CODE too.

kripken avatar Nov 12 '16 18:11 kripken

Ah I see. Is there somewhere a standalone example or do I need to defiddle the .js file?

bodokaiser avatar Nov 12 '16 18:11 bodokaiser

We don't really have a good way to generate a standalone wasm file yet from C or C++. As I said, you can try emcc's ONLY_MY_CODE, but it's not likely to work. This is an area that needs more work. It's just not easy to do, as C and C++ programs tend to need things we can't do in pure wasm right now, like print. But, we could define a new ABI that makes it practical, I think.

Alternatively, if you're not using C or C++, then you can use binaryen directly to generate code, and then you can generate exactly what you want in terms of imports and exports and code. The mir2wasm project is doing that for Rust, for example.

kripken avatar Nov 12 '16 18:11 kripken

Is there actually some minimal js file available which will work with asm.js and .wasm?

bodokaiser avatar Nov 15 '16 13:11 bodokaiser

What do you mean "work with asm.js and wasm"?

kripken avatar Nov 15 '16 18:11 kripken

It would be nice to have a minimal html+js for

  • only asm.js
  • only wasm
  • wasm and asm as fallback

bodokaiser avatar Nov 15 '16 18:11 bodokaiser

And what do you mean by minimal? Something smaller than emcc generates for you?

As explained above, we don't have a way to have a truly standalone wasm file, so something smaller than emcc generates isn't yet possible.

However, I am working on dynamic linking of wasm now, and that might be a route to get there. On the linking branch in this repo and binaryen-linking branches in emscripten and emscripten-fastcomp, basic shared modules of wasm are starting to work. We could in fact create a mostly standalone way to load those, with some ABI definitions. Still things to figure out though like the C stack.

kripken avatar Nov 15 '16 18:11 kripken

@kripken

By default emcc will generate a .js file that will instantiate the wasm module and pass it the necessary imports automatically for you.

I'm using following command to compile

emcc counter.c -s WASM=1 -s SIDE_MODULE=1 -o counter.wasm

Getting .wasm file from it, but no .js file. What did I miss?

art-in avatar Jun 27 '17 20:06 art-in

Ok. I simply did not have to use SIDE_MODULE flag (which is obviously opposite to 'by default').
This works fine

emcc counter.c -s WASM=1 -o counter.js

art-in avatar Jun 28 '17 09:06 art-in

I made it work after reading some Google tutorial https://codelabs.developers.google.com/codelabs/web-assembly-intro/index.html?index=..%2F..%2Findex#3

// hello.c
#include <stdio.h>

float bezier1(float t, float p0, float p1) {
    return (1 - t) * p0 + t * p1;
}
emcc hello.c -s ONLY_MY_CODE=1 -s WASM=1 -s EXPORTED_FUNCTIONS="['_bezier1']"  -o hello.js

I didn't understand why I have to use underscore in function name and why I have to create a JS file. But it works.

Finally, my JS code:

const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 });
const importObj = {
    env: {
        abortStackOverflow: () => { throw new Error('overflow'); },
        table: new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' }),
        tableBase: 0,
        memory: memory,
        memoryBase: 1024,
        STACKTOP: 0,
        STACK_MAX: memory.buffer.byteLength,
    }
};
fetch('hello.wasm').then((response) => response.arrayBuffer())
    .then((bytes) => WebAssembly.instantiate(bytes, importObj))
    .then((wa) => alert(wa.instance.exports._bezier1(0.5, 10, 20)));

Overall I think there is so much overkill. As far as WebAssembly is supported in all the modern browsers I expect to just doing something like npm install c-to-wasm and then node node_modules/.bin/c-to-wasm index.c index.wasm. Installing all that tools, containing python etc. and doing OS specific tricks seems strange for mainstream web development toolchain.

alexanderby avatar Nov 15 '17 10:11 alexanderby

@alexanderby

Installing all that tools, containing python etc. and doing OS specific tricks seems strange for mainstream web development toolchain.

I think so too but I suspect there will be a period of bootstrapping and then the language revolution should take off. The fact that you can use binaryen to dynamically compile subsequent wasm leads me to think there is an opportunity for radically new toolchains.

justinmchase avatar Dec 02 '17 06:12 justinmchase

If you get an error like this (with alexanderbys code): Uncaught (in promise) LinkError: WebAssembly Instantiation: Import #1 module="env" function="__memory_base" error: global import must be a number or WebAssembly.Global object:

https://github.com/googlecodelabs/web-assembly-introduction/issues/11

KargJonas avatar Feb 18 '19 09:02 KargJonas

1 Uncaught (in promise) TypeError: WebAssembly.instantiate(): Import #0 module="wasi_snapshot_preview1" error: module is not an object or function

georginzhang avatar Dec 10 '21 03:12 georginzhang