Skip to content

Linkage errors with bindings for structs passed by value generated by bindgen on wasm32-unknown-unknown #2590

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

Closed
nwoods-cimpress opened this issue Jul 24, 2023 · 2 comments

Comments

@nwoods-cimpress
Copy link

nwoods-cimpress commented Jul 24, 2023

Input C

struct Packet
{
    long long x;
    float y;
};

double frob(struct Packet packet);```

Bindgen Invocation

    bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("src/frobber.h")
        // Specify clang options
        .clang_arg("-fvisibility=default") // Needed for WebAssembly as per https://github.com/rust-lang/rust-bindgen/issues/2589
        .clang_arg("--target=wasm32-unknown-unknown")
        .allowlist_function("frob")
        // Tell cargo to invalidate the built crate whenever any of the
        // included header files changed.
        .parse_callbacks(Box::new(bindgen::CargoCallbacks))
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .unwrap()
        .write_to_file("src/frobber_bindings.rs")
        .unwrap();

Actual Results

Major caveat below!

extern "C" {
    pub fn frob(packet: Packet) -> f64;
}

Under normal circumstances, the actual results are exactly what I would expect. However, when linking under wasm32-unknown-unknown I get these results:

  = note: rust-lld: error: function signature mismatch: frob
          >>> defined as (i64, f32) -> f64 in C:\dev\wasm_link_test\target\wasm32-unknown-unknown\release\deps\wasm_link_test.wasm_link_test.4f5e81ff432209fe-cgu.2.rcgu.o
          >>> defined as (i32) -> f64 in C:\dev\wasm_link_test\target\wasm32-unknown-unknown\release\build\wasm_link_test-2cc6822d683d0def\out\libfrobber.a(frobber.o)

These results would suggest that Rust is passing the Packet object by value by breaking it up and passing each parameter as independent values. Manually tweaking the generated bindings to to pass packet by references (as per "Expected results" below).

All this said, I don't understand why a problem like this would be specific to WebAssembler. Pretty much every ABI on every platform I've worked with involves passing non-trivial structs by value using a hidden reference. So based on my understanding of this problem, I'd expect this issue to affect all platforms (which is clearly not happening).

I have read your disclaimer regarding certain C++ ABIs (e.g. - Itanium and MSVC). For this reason I was keen on demonstrating this problem with normal C code.

Expected Results

Not really what I would expect of course, but this seems to sidestep the problem

extern "C" {
    pub fn frob(packet: &Packet) -> f64;
}
@pvdrz
Copy link
Contributor

pvdrz commented Jul 24, 2023

This seems to be related: WebAssembly/tool-conventions#130

@nwoods-cimpress
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants