Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc disagrees with emcc about WASM struct ABI in parameters #88152

Open
Manishearth opened this issue Aug 19, 2021 · 5 comments
Open

rustc disagrees with emcc about WASM struct ABI in parameters #88152

Manishearth opened this issue Aug 19, 2021 · 5 comments
Labels
C-bug Category: This is a bug. O-wasm Target: WASM (WebAssembly), http://webassembly.org/

Comments

@Manishearth
Copy link
Member

I have the following Rust code, being compiled with cargo +nightly build --target wasm32-unknown-unknown

// in crate "em"

#[repr(C)]
pub struct Options {
    a: u8,
    b: u8
}

#[no_mangle]
pub extern "C" fn take_struct(o: Options) {}

And the following C++ code, compiled with emcc -std=c++17 test.cpp target/wasm32-unknown-unknown/debug/libem.a -ldl -lpthread -lm -g -o main.html --emrun -sWASM=1 (using the emscripten sdk)

# test.cpp 
extern "C" {
    typedef struct Options {
        uint8_t a;
        uint8_t b;
    } Options;
    void take_struct(Options o);
}

int main() {
    Options o;
    take_struct(o);
    return 0;
}

I expected to see this happen: The code would compile without warnings and run fine.

Instead, this happened:

emcc shows up the following warning:

wasm-ld: warning: function signature mismatch: take_struct
>>> defined as (i32) -> void in /tmp/emscripten_temp_qz2pbc3_/test_0.o
>>> defined as (i32, i32) -> void in target/wasm32-unknown-unknown/debug/libem.a(em.zb05z167nruq6bs.rcgu.o)

and running main.html in the browser throws the following error (to be expected based on the warning)

exception thrown: RuntimeError: unreachable,RuntimeError: unreachable
    at signature_mismatch:take_struct (http://localhost:8000/main.wasm:wasm-function[1]:0x165)
    at __original_main (http://localhost:8000/main.wasm:wasm-function[2]:0x1f1)
    at main (http://localhost:8000/main.wasm:wasm-function[3]:0x20e)
    at http://localhost:8000/main.js:1560:22
    at callMain (http://localhost:8000/main.js:2142:15)
    at doRun (http://localhost:8000/main.js:2212:23)
    at http://localhost:8000/main.js:2223:7

Seems like rustc believes that the signature for fn({u8, u8}) should be (i32, i32) -> void, whereas emcc believes it should be (i32) -> void.

A lot of other function signatures work (including returning Option), it's specifically when such a struct is a parameter that this happens.

I'm not sure which side is at fault here, but an incompatibility between Rust and emcc means that it won't be possible to use WASM with C++ programs that embed a little Rust (or vice versa), which seems like a problem worth highlighting. I think there are other ways to compile C++ to WASM via clang that I need to check out next.

Meta

Version info
$ rustc --version --verbose
rustc 1.56.0-nightly (2d2bc94c8 2021-08-15)
binary: rustc
commit-hash: 2d2bc94c8c3aa778e191f80261c726e4777439f1
commit-date: 2021-08-15
host: x86_64-unknown-linux-gnu
release: 1.56.0-nightly
LLVM version: 12.0.1
$ emcc --version
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 2.0.27 (7e538a419c3649f3a540a57beab347aa8f6c6271)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

cc @fitzgen

@Manishearth Manishearth added O-wasm Target: WASM (WebAssembly), http://webassembly.org/ C-bug Category: This is a bug. labels Aug 19, 2021
@Manishearth
Copy link
Member Author

This might be because I'm building with --target wasm32-unknown-unknown, however under wasm32-unknown-emscripten I get a bunch of link errors so it seems like that's not well suited for this:

  = note: emcc: warning: please replace -g4 with -gsource-map [-Wdeprecated]
          error: undefined symbol: __gxx_personality_v0 (referenced by top-level compiled C/C++ code)
          warning: Link with `-s LLD_REPORT_UNDEFINED` to get more information on undefined symbols
          warning: To disable errors for undefined symbols use `-s ERROR_ON_UNDEFINED_SYMBOLS=0`
          warning: ___gxx_personality_v0 may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library
          error: undefined symbol: main (referenced by top-level compiled C/C++ code)
          warning: _main may need to be added to EXPORTED_FUNCTIONS if it arrives from a system library
          warning: To build in STANDALONE_WASM mode without a main(), use emcc --no-entry
          Error: Aborting compilation due to previous errors
          emcc: error: '/home/manishearth/Installs/emsdk/node/14.15.5_64bit/bin/node /home/manishearth/Installs/emsdk/upstream/emscripten/src/compiler.js /tmp/tmpf5dpw2l1.txt' failed (returned 1)

@workingjubilee
Copy link
Member

Relevant commentary in #83763

@fitzgen
Copy link
Member

fitzgen commented Aug 19, 2021

Yeah, this is an unfortunate historical mistake, but one which can't be fixed without breaking a bunch of code (everything that uses wasm-bindgen).

The wasm32-wasi target agrees with clang's wasm32-wasi target, fwiw, and linking C and Rust on that target is trivial.

I don't know anything about the emscripten target.

@Manishearth
Copy link
Member Author

@fitzgen thanks!

and linking C and Rust on that target is trivial.

Seems like C++ is a bit more challenging, can't get iostream to work.

@gregbuchholz
Copy link

@Manishearth the Emscripten link errors you were getting can be solved using this tip, or this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. O-wasm Target: WASM (WebAssembly), http://webassembly.org/
Projects
None yet
Development

No branches or pull requests

4 participants