Zachary Whitley
Zachary Whitley

Reputation: 35

Is there a way to inspect a wasm module for imports

Let me explain a little bit about what I'm doing. I have an application that I'm embedding a wasm engine (specifically wasmtime) and writing the wasm in Rust. The target is not a browser so I'm not using wasm-bindgen. I'm trying to import two functions from the host environment. I've gotten it to work but with a bit of a hack and I'd like to remove the hack. Here's the problem I'm having. I've been able to figure out how to get Rust to generate the import statements in the wasm output. The problem is that if those functions aren't used the import statements in the wasm aren't included. Wasmtime seem to require that the number of imports passed to the wasm instance match the number of import statements. Makes sense that if the wasm module is expecting imports it's a problem if you don't provide them. The problem is, it's also an error if you provide imports and they're not used.

So I see two ways to fix that, either I need to figure out how to get Rust to include the import statements even if they're not used (right now the hack is to call the functions but ignore the results and it's basically a no-op) or to find a way to introspect the wasm an figure out what kind of imports it's expecting and only pass what it's asking for.

My question is is that the correct approach and if so how do you do that?

Upvotes: 1

Views: 3332

Answers (3)

5422m4n
5422m4n

Reputation: 950

I have used a 2 step approach with the wasm-tools.

1. check the overview of symbols with wasm-tools objdump

❯ wasm-tools objdump mywasm.wasm

custom "\0ozzzzz_metadata"             |       0x1b -       0x1e |         3 bytes | 1 count
  types                                  |       0x21 -      0x286 |       613 bytes | 78 count
  imports                                |      0x289 -      0x8da |      1617 bytes | 42 count
  functions                              |      0x8dd -     0x2a16 |      8505 bytes | 8503 count
  tables                                 |     0x2a18 -     0x2a1f |         7 bytes | 1 count
  memories                               |     0x2a21 -     0x2a25 |         4 bytes | 1 count
  globals                                |     0x2a27 -     0x2a35 |        14 bytes | 2 count
  exports                                |     0x2a37 -     0x2a4a |        19 bytes | 2 count
  elements                               |     0x2a4d -     0x4fd5 |      9608 bytes | 1 count
  code                                   |     0x4fda -   0x374e69 |   3604111 bytes | 8503 count
  data                                   |   0x374e6e -   0xc9fea7 |   9613369 bytes | 2 count
  custom ".debug_loc"                    |   0xc9feb7 -   0xf22865 |   2632110 bytes | 1 count
  custom ".debug_abbrev"                 |   0xf22877 -   0xf5230e |    195223 bytes | 1 count
  custom ".debug_info"                   |   0xf5231f -  0x1600847 |   7005480 bytes | 1 count
  custom ".debug_ranges"                 |  0x1600859 -  0x1649691 |    298552 bytes | 1 count
  custom ".debug_str"                    |  0x16496a0 -  0x16dbb98 |    599288 bytes | 1 count
  custom ".debug_line"                   |  0x16dbba9 -  0x1953495 |   2586860 bytes | 1 count
  custom "name"                          |  0x195349e -  0x197db8e |    173808 bytes | 1 count
  custom "producers"                     |  0x197db9b -  0x197dc16 |       123 bytes | 1 count
  custom "target_features"               |  0x197dc28 -  0x197dc51 |        41 bytes | 1 count

2. checking the imports specifically

❯ wasm-tools dump mywasm.wasm | grep import

     0x286 | 02 d1 0c    | import section
     0x28a | 16 77 61 73 | import [func 0] Import { module: "wasi_snapshot_preview1", name: "args_get", ty: Func(2) }
     0x2ac | 16 77 61 73 | import [func 1] Import { module: "wasi_snapshot_preview1", name: "args_sizes_get", ty: Func(2) }
     0x2d4 | 16 77 61 73 | import [func 2] Import { module: "wasi_snapshot_preview1", name: "environ_get", ty: Func(2) }
     0x2f9 | 16 77 61 73 | import [func 3] Import { module: "wasi_snapshot_preview1", name: "environ_sizes_get", ty: Func(2) }
 
 [...]

But regarding your question, I would verify if your functions that your rust project should have been provided are missing. E.g. all extern "C" fn that are annotated with #[no_mangle] should appear in the listing below:

❯ wasm-tools dump mywasm.wasm | grep export | grep 'kind: Func'

    0x2a41 | 06 5f 73 74 | export Export { name: "_start", kind: Func, index: 43 }

In order that wasmtime can execute your wasm it needs this _start entry point.

Upvotes: 1

Nikolay Handzhiyski
Nikolay Handzhiyski

Reputation: 1579

You can convert between .wasm (binary format) and .wat (textual format) with the The WebAssembly Binary Toolkit. It is open source. Maybe it can help you to extract the needed imports programmatically.

The proper way, should be that your host environment gives you the import requirements before you initialize the instance. The Module gives you the imports. See the "Instance variables". You get that in between the module loading and the creation of the instance that itself needs these imports.

Upvotes: 3

sbc100
sbc100

Reputation: 3032

To find the imports of a wasm module you can you use a command line tool that converts the .wasm to .wat and inspect the wat file (using grep or similar). For example wasm-dis which is part of binaryen or wasm2wat which is part of wabt could be used (or wasm-objdump which is also part of wabt).

Upvotes: 0

Related Questions