From c01e07977a7a07b4975a7338a81610a9b1404c7d Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 23 Feb 2023 19:20:17 -0800 Subject: [PATCH] Separate out barebones WASI impl --- src/interp.rs | 73 +++++++++------------------------------------- src/interp/wasi.rs | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 60 deletions(-) create mode 100644 src/interp/wasi.rs diff --git a/src/interp.rs b/src/interp.rs index c4070cf..f117468 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -7,6 +7,8 @@ use smallvec::{smallvec, SmallVec}; use std::collections::HashMap; +mod wasi; + #[derive(Debug, Clone)] pub struct InterpContext { memories: PerEntity, @@ -201,59 +203,10 @@ impl InterpContext { } fn call_import(&mut self, name: &str, args: &[ConstVal]) -> Option> { - let mem = &mut self.memories[Memory::from(0)]; - match name { - "__wasi_fd_prestat_get" => { - Some(smallvec![ConstVal::I32(8)]) // BADF - } - "__wasi_args_sizes_get" => { - let p_argc = args[0].as_u32().unwrap(); - let p_argv_size = args[1].as_u32().unwrap(); - write_u32(mem, p_argc, 0); - write_u32(mem, p_argv_size, 0); - Some(smallvec![ConstVal::I32(0)]) - } - "__wasi_args_get" => Some(smallvec![ConstVal::I32(0)]), - "__wasi_fd_fdstat_get" => { - let fd = args[0].as_u32().unwrap(); - let p_fdstat_t = args[1].as_u32().unwrap(); - if fd == 1 { - write_u32(mem, p_fdstat_t + 0, 2); // filetype = CHAR - write_u32(mem, p_fdstat_t + 4, 0); // flags = 0 - write_u32(mem, p_fdstat_t + 8, 0x40); // rights_base = WRITE - write_u32(mem, p_fdstat_t + 12, 0); // rights_inheriting = 0 - Some(smallvec![ConstVal::I32(0)]) - } else { - None - } - } - "__wasi_fd_write" => { - let fd = args[0].as_u32().unwrap(); - let p_iovs = args[1].as_u32().unwrap(); - let iovs_len = args[2].as_u32().unwrap(); - let p_nwritten = args[3].as_u32().unwrap(); - if fd == 1 { - let mut written = 0; - for i in 0..iovs_len { - let iov_entry = p_iovs + 8 * i; - let base = read_u32(mem, iov_entry) as usize; - let len = read_u32(mem, iov_entry + 4) as usize; - let data = &mem.data[base..(base + len)]; - print!("{}", std::str::from_utf8(data).unwrap()); - written += len; - } - write_u32(mem, p_nwritten, written as u32); - Some(smallvec![ConstVal::I32(0)]) - } else { - None - } - } - "__wasi_proc_exit" => { - eprintln!("WASI exit: {:?}", args[0]); - None - } - _ => panic!("Unknown import: {} with args: {:?}", name, args), + if let Some(ret) = wasi::call_wasi(&mut self.memories[Memory::from(0)], name, args) { + return Some(ret); } + panic!("Unknown import: {} with args: {:?}", name, args); } } @@ -888,45 +841,45 @@ pub fn const_eval( } } -fn read_u8(mem: &InterpMemory, addr: u32) -> u8 { +pub(crate) fn read_u8(mem: &InterpMemory, addr: u32) -> u8 { let addr = addr as usize; mem.data[addr] } -fn read_u16(mem: &InterpMemory, addr: u32) -> u16 { +pub(crate) fn read_u16(mem: &InterpMemory, addr: u32) -> u16 { use std::convert::TryInto; let addr = addr as usize; u16::from_le_bytes(mem.data[addr..(addr + 2)].try_into().unwrap()) } -fn read_u32(mem: &InterpMemory, addr: u32) -> u32 { +pub(crate) fn read_u32(mem: &InterpMemory, addr: u32) -> u32 { use std::convert::TryInto; let addr = addr as usize; u32::from_le_bytes(mem.data[addr..(addr + 4)].try_into().unwrap()) } -fn read_u64(mem: &InterpMemory, addr: u32) -> u64 { +pub(crate) fn read_u64(mem: &InterpMemory, addr: u32) -> u64 { use std::convert::TryInto; let addr = addr as usize; u64::from_le_bytes(mem.data[addr..(addr + 8)].try_into().unwrap()) } -fn write_u8(mem: &mut InterpMemory, addr: u32, data: u8) { +pub(crate) fn write_u8(mem: &mut InterpMemory, addr: u32, data: u8) { let addr = addr as usize; mem.data[addr] = data; } -fn write_u16(mem: &mut InterpMemory, addr: u32, data: u16) { +pub(crate) fn write_u16(mem: &mut InterpMemory, addr: u32, data: u16) { let addr = addr as usize; mem.data[addr..(addr + 2)].copy_from_slice(&data.to_le_bytes()[..]); } -fn write_u32(mem: &mut InterpMemory, addr: u32, data: u32) { +pub(crate) fn write_u32(mem: &mut InterpMemory, addr: u32, data: u32) { let addr = addr as usize; mem.data[addr..(addr + 4)].copy_from_slice(&data.to_le_bytes()[..]); } -fn write_u64(mem: &mut InterpMemory, addr: u32, data: u64) { +pub(crate) fn write_u64(mem: &mut InterpMemory, addr: u32, data: u64) { let addr = addr as usize; mem.data[addr..(addr + 8)].copy_from_slice(&data.to_le_bytes()[..]); } diff --git a/src/interp/wasi.rs b/src/interp/wasi.rs new file mode 100644 index 0000000..4ba5a98 --- /dev/null +++ b/src/interp/wasi.rs @@ -0,0 +1,63 @@ +//! Very basic WASI implementation for interpreter: sufficient to let stdout work. + +use crate::interp::{read_u32, write_u32, ConstVal, InterpMemory}; +use smallvec::{smallvec, SmallVec}; + +pub fn call_wasi( + mem: &mut InterpMemory, + name: &str, + args: &[ConstVal], +) -> Option> { + match name { + "__wasi_fd_prestat_get" => { + Some(smallvec![ConstVal::I32(8)]) // BADF + } + "__wasi_args_sizes_get" => { + let p_argc = args[0].as_u32().unwrap(); + let p_argv_size = args[1].as_u32().unwrap(); + write_u32(mem, p_argc, 0); + write_u32(mem, p_argv_size, 0); + Some(smallvec![ConstVal::I32(0)]) + } + "__wasi_args_get" => Some(smallvec![ConstVal::I32(0)]), + "__wasi_fd_fdstat_get" => { + let fd = args[0].as_u32().unwrap(); + let p_fdstat_t = args[1].as_u32().unwrap(); + if fd == 1 { + write_u32(mem, p_fdstat_t + 0, 2); // filetype = CHAR + write_u32(mem, p_fdstat_t + 4, 0); // flags = 0 + write_u32(mem, p_fdstat_t + 8, 0x40); // rights_base = WRITE + write_u32(mem, p_fdstat_t + 12, 0); // rights_inheriting = 0 + Some(smallvec![ConstVal::I32(0)]) + } else { + None + } + } + "__wasi_fd_write" => { + let fd = args[0].as_u32().unwrap(); + let p_iovs = args[1].as_u32().unwrap(); + let iovs_len = args[2].as_u32().unwrap(); + let p_nwritten = args[3].as_u32().unwrap(); + if fd == 1 { + let mut written = 0; + for i in 0..iovs_len { + let iov_entry = p_iovs + 8 * i; + let base = read_u32(mem, iov_entry) as usize; + let len = read_u32(mem, iov_entry + 4) as usize; + let data = &mem.data[base..(base + len)]; + print!("{}", std::str::from_utf8(data).unwrap()); + written += len; + } + write_u32(mem, p_nwritten, written as u32); + Some(smallvec![ConstVal::I32(0)]) + } else { + None + } + } + "__wasi_proc_exit" => { + eprintln!("WASI exit: {:?}", args[0]); + None + } + _ => None, + } +}