Skip to content

Q: Compiling binaryen-c to just a .wasm #1380

Closed

Description

@dcodeIO

I am currently toying around with this because, erm, weekend, but I am probably doing it wrong. Intention is to take binaryen-c, libc, libcxx etc., make a standalone .wasm of it (without a distinct JS wrapper, that's why I'm trying SIDE_MODULE) and then implement whatever imports are still missing on the JS side and plug it into binaryen.js as the underlying C-API.

My command line looks like this (most of the parameters are just those used in the JS build, reusing shared.bc generated there):

em++ \
 -s DEMANGLE_SUPPORT=1 \
 -s DISABLE_EXCEPTION_CATCHING=0 \
 --memory-init-file 0 \
 --llvm-lto 1 \
 -std=c++11 \
 -s EXPORTED_FUNCTIONS=[...] \
 -s ALLOW_MEMORY_GROWTH=1 \
 -s BINARYEN=1 \
 -s BINARYEN_METHOD='native-wasm' \
 -s SIDE_MODULE=1 \
 -o binaryen.wasm \
 shared.bc \
 dlmalloc.bc \
 libc.bc \
 libcxx.a \
 libcxxabi.bc \

Resulting in

[wasm-validator error in module] unexpected false: module function exports must be found, on
$___optreset
[wasm-validator error in module] unexpected false: module function exports must be found, on
$___progname_full
[wasm-validator error in module] unexpected false: module function exports must be found, on
$___progname
[wasm-validator error in module] unexpected false: module function exports must be found, on
$___signgam

followed by about 45 mb of wast validation output.

Other issues I see are that a temporary binaryen.asm.js file is being generated in the process, which is unexpected to me because I am targeting wasm with binaryen only, and that all of the things in libc.bc etc. seem to be exported (probably missing a linking step?).

Do you have some hints for me? :)

Activity

  1. kripken commented on Jan 20, 2018

    @kripken
    Member
    1. You might need to implement a bunch of things for the imports here - e.g. binaryen uses exceptions so there will be invokes, and it does syscalls to print logging, etc. Not sure it will be practical to do. But could be fun to try :)
    2. You actually can just build with -Os on latest emscripten, you don't need SIDE_MODULE. It should still produce something with the minimal possible imports and exports (thanks to metadce). SIDE_MODULE will bring in some extra overhead, too, like runtime relocations (for memory and the table) which you don't need. And with -Os --closure 1 the generated JS should be pretty minimal, especially compared to the wasm size (blogpost coming on this soon).
    3. A temporary asm.js file is expected, we generate asm.js and then run asm2wasm to get wasm.
    4. That crash is due to libc aliases for globals, possible fix is in emscripten-core/emscripten@dc543e9
  2. dcodeIO commented on Jan 20, 2018

    @dcodeIO
    ContributorAuthor

    That crash is due to libc aliases for globals

    Works with the fix! :)

  3. dcodeIO commented on Jan 20, 2018

    @dcodeIO
    ContributorAuthor

    You might need to implement a bunch of things for the imports here - e.g. binaryen uses exceptions so there will be invokes, and it does syscalls to print logging, etc. Not sure it will be practical to do.

    Yeah, you are right. Isn't practical, especially when Emscripten already does all of this.

    I have a working WASM version now, but it required a couple of changes to binaryen.js-post.js to work, because the post-js immediately calls some exports (like when setting up Module['i32'] = _BinaryenTypeInt32()) without waiting for the module to become ready. While all of this is straight forward, now I'm not sure if MODULARIZE/MODULARIZE_INSTANCE should handle such conditions automatically (not running post-js at all until the module is ready) or if it's better to just patch it into post-js using onRuntimeInitialized. What'd you say?

    I have an API in mind now that, when loading binaryen.js the usual way, you get an instance of the JS interface. The JS interface could then also provide an instantiateWasm function or something that one could use to lazily get an API that's backed by WASM instead. But that might change, still trying out all sorts of things :)

  4. kripken commented on Jan 20, 2018

    @kripken
    Member

    Yeah, the async startup is an annoying issue. For binaryen.js we can maybe just set BINARYEN_ASYNC_COMPILATION=0 so it is synchronous - browsers have limits there, but hopefully node.js doesn't. Does that work?

    (Otherwise, MODULARIZE provides a promise for this, but it's not clear how to do that with MODULARIZE_INSTANCE...)

  5. dcodeIO commented on Jan 20, 2018

    @dcodeIO
    ContributorAuthor

    e.g. binaryen uses exceptions so there will be invokes, and it does syscalls to print logging, etc.

    I remember that exception catching wasn't enabled when building binaryen.js not long ago, but I'm not sure how relevant this is. I wonder if it would it be possible to simplify these parts on the C/C++ side so it becomes easier to link with the wasm version? Asking because I intend to link Binaryen compiled to WASM with the AssemblyScript compiler compiled to WASM, making it a single binary, eventually.

  6. kripken commented on Jan 22, 2018

    @kripken
    Member

    I think over time the JS side will get simpler, for example when wasm has native C++ exceptions support, we won't need invokes etc.

  7. dcodeIO commented on Feb 16, 2018

    @dcodeIO
    ContributorAuthor

    Thanks for the insights! Closing while waiting for the specs to land :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions