forked from wasmerio/wasmer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
memory.rs
149 lines (124 loc) · 5.01 KB
/
memory.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! With Wasmer you'll be able to interact with guest module memory.
//!
//! This example illustrates the basics of interacting with Wasm module memory.:
//!
//! 1. How to load a Wasm modules as bytes
//! 2. How to compile the module
//! 3. How to create an instance of the module
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```shell
//! cargo run --example memory --release --features "cranelift"
//! ```
//!
//! Ready?
use std::mem;
use wasmer::{imports, wat2wasm, Bytes, Instance, Module, Pages, Store, TypedFunction};
// this example is a work in progress:
// TODO: clean it up and comment it https://github.com/wasmerio/wasmer/issues/1749
fn main() -> anyhow::Result<()> {
// Let's declare the Wasm module.
//
// We are using the text representation of the module here but you can also load `.wasm`
// files using the `include_bytes!` macro.
let wasm_bytes = wat2wasm(
r#"
(module
(type $mem_size_t (func (result i32)))
(type $get_at_t (func (param i32) (result i32)))
(type $set_at_t (func (param i32) (param i32)))
(memory $mem 1)
(func $get_at (type $get_at_t) (param $idx i32) (result i32)
(i32.load (local.get $idx)))
(func $set_at (type $set_at_t) (param $idx i32) (param $val i32)
(i32.store (local.get $idx) (local.get $val)))
(func $mem_size (type $mem_size_t) (result i32)
(memory.size))
(export "get_at" (func $get_at))
(export "set_at" (func $set_at))
(export "mem_size" (func $mem_size))
(export "memory" (memory $mem)))
"#
.as_bytes(),
)?;
// Create a Store.
let mut store = Store::default();
println!("Compiling module...");
// Let's compile the Wasm module.
let module = Module::new(&store, wasm_bytes)?;
// Create an empty import object.
let import_object = imports! {};
println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&mut store, &module, &import_object)?;
// The module exports some utility functions, let's get them.
//
// These function will be used later in this example.
let mem_size: TypedFunction<(), i32> = instance
.exports
.get_typed_function(&mut store, "mem_size")?;
let get_at: TypedFunction<i32, i32> =
instance.exports.get_typed_function(&mut store, "get_at")?;
let set_at: TypedFunction<(i32, i32), ()> =
instance.exports.get_typed_function(&mut store, "set_at")?;
let memory = instance.exports.get_memory("memory")?;
// We now have an instance ready to be used.
//
// We will start by querying the most intersting information
// about the memory: its size. There are mainly two ways of getting
// this:
// * the size as a number of `Page`s
// * the size as a number of bytes
//
// The size in bytes can be found either by querying its pages or by
// querying the memory directly.
println!("Querying memory size...");
let memory_view = memory.view(&store);
assert_eq!(memory_view.size(), Pages::from(1));
assert_eq!(memory_view.size().bytes(), Bytes::from(65536 as usize));
assert_eq!(memory_view.data_size(), 65536);
// Sometimes, the guest module may also export a function to let you
// query the memory. Here we have a `mem_size` function, let's try it:
let result = mem_size.call(&mut store)?;
let memory_view = memory.view(&store);
println!("Memory size: {:?}", result);
assert_eq!(Pages::from(result as u32), memory_view.size());
// Now that we know the size of our memory, it's time to see how wa
// can change this.
//
// A memory can be grown to allow storing more things into it. Let's
// see how we can do that:
println!("Growing memory...");
// Here we are requesting two more pages for our memory.
memory.grow(&mut store, 2)?;
let memory_view = memory.view(&store);
assert_eq!(memory_view.size(), Pages::from(3));
assert_eq!(memory_view.data_size(), 65536 * 3);
// Now that we know how to query and adjust the size of the memory,
// let's see how wa can write to it or read from it.
//
// We'll only focus on how to do this using exported functions, the goal
// is to show how to work with memory addresses. Here we'll use absolute
// addresses to write and read a value.
let mem_addr = 0x2220;
let val = 0xFEFEFFE;
set_at.call(&mut store, mem_addr, val)?;
let result = get_at.call(&mut store, mem_addr)?;
println!("Value at {:#x?}: {:?}", mem_addr, result);
assert_eq!(result, val);
// Now instead of using hard coded memory addresses, let's try to write
// something at the end of the second memory page and read it.
let page_size = 0x1_0000;
let mem_addr = (page_size * 2) - mem::size_of_val(&val) as i32;
let val = 0xFEA09;
set_at.call(&mut store, mem_addr, val)?;
let result = get_at.call(&mut store, mem_addr)?;
println!("Value at {:#x?}: {:?}", mem_addr, result);
assert_eq!(result, val);
Ok(())
}
#[test]
fn test_memory() -> anyhow::Result<()> {
main()
}