How are structs represented in web assembly?

I'm writing a network driver for the PCE* Gigabit ethernet controllers by Intel (the Intel 82571EB/82572EI, 631xESB/632xESB, 82563EB/82564EB, and 82573E/82573V/82573L). I might need to define structs that need to be exposed to an execution environment (e.g.: a kernel). How does Rust encode these, since WASM only has 32/64-bit ints and floats?

WASM has linear memory just like the x86 and the ARM. Even x86 doesn't support structs, it can only have integers and floats on registers.

2 Likes

I know that. I'm just wondering how they're represented in a WASM module, e.g.: can I extract them, or how would I read from them, that kind of thing.

You probably shouldn't try to do it directly, since they might be represented in different ways - just like in x86/ARM memory the Rust struct can have multiple representations, depending, for example, on compiler version (if it's not repr(C), of course). It can even be partially inlined, i.e. not being fully stored in memory for some time, passing its parts around instead.

If you want your data to be accessible from outside, it's better to simply define the public function which will serialize them to some known format.

The WASM basic C ABI specifies the details of how #[repr(C)] structs are laid out and passed. It's pretty similar to other 32-bit platforms.

2 Likes

Be warned that on wasm32-unknown-unknown rustc doesn't follow the WASM basic C ABI for the calling convention. Rustc does follow it for the memory representation though and it follows if for the calling convention too for wasm32-unknown-emscripten and wasm32-wasi.

1 Like

Even on extern "C" functions, or are you talking about extern "Rust"? Is there any way to access the WASM basic C ABI?

Even for extern "C". It is not possible to access the wasm basic C abi with wasm32-unknown-unknown. Due to a historic accident a different abi was used and now we are stuck as wasm-bindgen depends on the current abi.

1 Like

See the discussion in issue 79998 for more information. Apparently they'll all sync up "soon" (where soon > a few months). Note that contrary to the OP in that issue, the PR as accepted (which will hit Rust 1.51 in a few weeks) doesn't make non-bindgen the default, it's just the part that makes WASI follow the calling convention (as enscripten already does).

1 Like

Wow, fascinating. So does that mean I can pass around structs from rust->WASM and vice-versa?

If you and some other library can agree on an ABI, you can pass structs back and forth. For rustc compiling the wasm32-unknown-unknown target right now, that seems that means you're limited to the "wasm-bindgen" API. Where as really you would want the WASM basic C abi, so you could be compatible with e.g. clang. There's yet more discussion in rustwasm issue 291, for e.g. someone who wants to compile a Rust + C program to WASM.

I suggest reading that issue through to get a feel for the current state of things. I'm not an expert but the TL;DR seems to be that, in practical terms, the compatibility is possible in some cases (enscripten), getting close in others (wasi), and being aimed at for the general case (wasm32-unknown-unknown), but overall not quite where one would hope it to be.