1 #![no_std]
2 
3 #[macro_use]
4 extern crate alloc;
5 
6 use alloc::string::ToString;
7 use anyhow::{Result, ensure};
8 use core::ptr;
9 use wasmtime::{Config, Engine, Instance, Linker, Module, Store};
10 
11 mod allocator;
12 mod panic;
13 
14 #[cfg(feature = "wasi")]
15 mod wasi;
16 
17 /// Entrypoint of this embedding.
18 ///
19 /// This takes a number of parameters which are the precompiled module AOT
20 /// images that are run for each of the various tests below. The first parameter
21 /// is also where to put an error string, if any, if anything fails.
22 #[unsafe(no_mangle)]
23 pub unsafe extern "C" fn run(
24     error_buf: *mut u8,
25     error_size: usize,
26     smoke_module: *const u8,
27     smoke_size: usize,
28     simple_add_module: *const u8,
29     simple_add_size: usize,
30     simple_host_fn_module: *const u8,
31     simple_host_fn_size: usize,
32     simple_floats_module: *const u8,
33     simple_floats_size: usize,
34 ) -> usize {
35     unsafe {
36         let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
37         let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
38         let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
39         let simple_host_fn =
40             core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
41         let simple_floats = core::slice::from_raw_parts(simple_floats_module, simple_floats_size);
42         match run_result(smoke, simple_add, simple_host_fn, simple_floats) {
43             Ok(()) => 0,
44             Err(e) => {
45                 let msg = format!("{e:?}");
46                 let len = buf.len().min(msg.len());
47                 buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
48                 len
49             }
50         }
51     }
52 }
53 
54 fn run_result(
55     smoke_module: &[u8],
56     simple_add_module: &[u8],
57     simple_host_fn_module: &[u8],
58     simple_floats_module: &[u8],
59 ) -> Result<()> {
60     smoke(smoke_module)?;
61     simple_add(simple_add_module)?;
62     simple_host_fn(simple_host_fn_module)?;
63     simple_floats(simple_floats_module)?;
64     Ok(())
65 }
66 
67 fn config() -> Config {
68     let mut config = Config::new();
69     let _ = &mut config;
70 
71     #[cfg(target_arch = "x86_64")]
72     {
73         // This example runs in a Linux process where it's valid to use
74         // floating point registers. Additionally sufficient x86 features are
75         // enabled during compilation to avoid float-related libcalls. Thus
76         // despite the host being configured for "soft float" it should be
77         // valid to turn this on.
78         unsafe {
79             config.x86_float_abi_ok(true);
80         }
81 
82         // To make the float ABI above OK it requires CPU features above
83         // baseline to be enabled. Wasmtime needs to be able to check to ensure
84         // that the feature is actually supplied at runtime, but a default check
85         // isn't possible in no_std. For x86_64 we can use the cpuid instruction
86         // bound through an external crate.
87         //
88         // Note that CPU support for these features has existed since 2013
89         // (Haswell) on Intel chips and 2012 (Piledriver) on AMD chips.
90         unsafe {
91             config.detect_host_feature(move |feature| {
92                 let id = raw_cpuid::CpuId::new();
93                 match feature {
94                     "sse3" => Some(id.get_feature_info()?.has_sse3()),
95                     "ssse3" => Some(id.get_feature_info()?.has_sse3()),
96                     "sse4.1" => Some(id.get_feature_info()?.has_sse41()),
97                     "sse4.2" => Some(id.get_feature_info()?.has_sse42()),
98                     "fma" => Some(id.get_feature_info()?.has_fma()),
99                     _ => None,
100                 }
101             });
102         }
103     }
104 
105     config
106 }
107 
108 fn smoke(module: &[u8]) -> Result<()> {
109     let engine = Engine::new(&config())?;
110     let module = match deserialize(&engine, module)? {
111         Some(module) => module,
112         None => return Ok(()),
113     };
114     Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
115     Ok(())
116 }
117 
118 fn simple_add(module: &[u8]) -> Result<()> {
119     let engine = Engine::new(&config())?;
120     let module = match deserialize(&engine, module)? {
121         Some(module) => module,
122         None => return Ok(()),
123     };
124     let mut store = Store::new(&engine, ());
125     let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
126     let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
127     ensure!(func.call(&mut store, (2, 3))? == 5);
128     Ok(())
129 }
130 
131 fn simple_host_fn(module: &[u8]) -> Result<()> {
132     let engine = Engine::new(&config())?;
133     let module = match deserialize(&engine, module)? {
134         Some(module) => module,
135         None => return Ok(()),
136     };
137     let mut linker = Linker::<()>::new(&engine);
138     linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
139     let mut store = Store::new(&engine, ());
140     let instance = linker.instantiate(&mut store, &module)?;
141     let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
142     ensure!(func.call(&mut store, (2, 3, 4))? == 10);
143     Ok(())
144 }
145 
146 fn simple_floats(module: &[u8]) -> Result<()> {
147     let engine = Engine::new(&config())?;
148     let module = match deserialize(&engine, module)? {
149         Some(module) => module,
150         None => return Ok(()),
151     };
152     let mut store = Store::new(&engine, ());
153     let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
154     let func = instance.get_typed_func::<(f32, f32), f32>(&mut store, "frob")?;
155     ensure!(func.call(&mut store, (1.4, 3.2))? == 5.);
156     Ok(())
157 }
158 
159 fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
160     let result = if cfg!(feature = "custom") {
161         // If a custom virtual memory system is in use use the raw `deserialize`
162         // API to let Wasmtime handle publishing the executable and such.
163         unsafe { Module::deserialize(engine, module) }
164     } else {
165         // NOTE: deserialize_raw avoids creating a copy of the module code. See
166         // the safety notes before using in your embedding.
167         //
168         // Also note that this will only work for native code with a custom code
169         // publisher which isn't configured in this example. Such custom code
170         // publisher will need to handle making this executable for example.
171         let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
172         let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
173         unsafe { Module::deserialize_raw(engine, module_memory) }
174     };
175     match result {
176         Ok(module) => Ok(Some(module)),
177         Err(e) => {
178             // Currently if custom signals/virtual memory are disabled then this
179             // example is expected to fail to load since loading native code
180             // requires virtual memory. In the future this will go away as when
181             // signals-based-traps is disabled then that means that the
182             // interpreter should be used which should work here.
183             if !cfg!(feature = "custom")
184                 && e.to_string()
185                     .contains("requires virtual memory to be enabled")
186             {
187                 Ok(None)
188             } else {
189                 Err(e)
190             }
191         }
192     }
193 }
194