Skip to content

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

Closed
@nwoods-cimpress

Description

@nwoods-cimpress

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;
}

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