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