Why are there "wasi_snapshot_preview_1" imports in this wasm module?
Asked Answered
S

1

8

Recently I tried to experiment with webassembly with as few helpers as possible.

So I created a c project, included some libraries (stb_image.h) and tried to compile it.

Here is a short reproducible example:

#include <emscripten.h>
#define STBI_NO_STDIO
#define STBI_NO_FAILURE_STRINGS
#define STB_IMAGE_IMPLEMENTATION

#include "stb_image.h"

EMSCRIPTEN_KEEPALIVE
void test(){
    stbi_load_from_memory(NULL, 0, NULL, NULL, NULL, 0);
}

Here is the command I used:

emcc converter.c -s STANDALONE_WASM -o converter.wasm --no-entry

This worked fine and gave me a valid wasm file.

But then I tried to instantiate it in a browser with javascript and nothing else:

let wasm = await Webassembly.instantiateStreaming(fetch('converter.wasm'), {});

But I get this error:

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

I inspected the webassembly, and indeed my webassembly need these functions:

  (func $wasi_snapshot_preview1.fd_close (;0;) (import "wasi_snapshot_preview1" "fd_close") (param i32) (result i32))
  (func $wasi_snapshot_preview1.fd_seek (;1;) (import "wasi_snapshot_preview1" "fd_seek") (param i32 i64 i32 i32) (result i32))
  (func $wasi_snapshot_preview1.fd_write (;2;) (import "wasi_snapshot_preview1" "fd_write") (param i32 i32 i32 i32) (result i32))
  (func $wasi_snapshot_preview1.proc_exit (;3;) (import "wasi_snapshot_preview1" "proc_exit") (param i32))

I understand that these are functions that are not supported in a pure wasm module (like os calls maybe ?) but I can't find any documentation on what each of them are exactly.

So my questions are:

  • What are these functions ?
  • Why do I need these imported functions if the stb_image header is supposed to just manipulate bits in the ram with no i/o ?
  • How can I tell my compiler to not use these functions (disabling the stdio library could work but I don't know how to do it)

Any insignt is apreciated !

EDIT

After experimenting with compilation of the c standard libraries, I understand what these functions are for:

  • fd_write is for printing (normally to the stdout in the os)
  • fd_seek and fd_close are for file manipulation

there is also fd_read to read a file but I don't need that in this code

  • proc_exit to terminate the process and potentially raise an error
Skuld answered 29/5, 2021 at 21:59 Comment(3)
Perhaps it's a bug or current limitation of emscripten.Latchkey
The STANDALONE_WASM flag instructs the compiler to build your module for WASI (the WebAssembly System Interface, which assumes you are not running in a browser, and interfaces with the underlying OS) - see v8.dev/blog/emscripten-standalone-wasm and bytecodealliance.org/articles/announcing-the-bytecode-alliance. If you remove the flag, your module should be compiled under the assumption it's going to get instantiated in a JavaScript runtime (browser, or Node.js).Chaplet
That did not fix my issue @radu-matei.Capuche
P
10

Firstly I would recommend building with -Oz or at least-O2 so that the toolchain tries is upmost to shrink the resulting binaryn.

I recommend building with -Oz --profiling-funcs and then using wasm-objdump or wasm-decompile to see why those imports and ultimately being used.

When I do this is clear that proc_exit is being used assert_fail .. indeed it looks like they are all due to the use of the assert macro and adding -DNDEBUG makes all those imports go away.

Palacios answered 2/6, 2021 at 16:23 Comment(1)
Thanks this works ! Could you add this line to your answer for completness: #define STBI_ASSERT(x) to say to the header library to never assert.Skuld

© 2022 - 2024 — McMap. All rights reserved.