Separate out barebones WASI impl

This commit is contained in:
Chris Fallin 2023-02-23 19:20:17 -08:00
parent 49a907da25
commit c01e07977a
2 changed files with 76 additions and 60 deletions

View file

@ -7,6 +7,8 @@ use smallvec::{smallvec, SmallVec};
use std::collections::HashMap;
mod wasi;
#[derive(Debug, Clone)]
pub struct InterpContext {
memories: PerEntity<Memory, InterpMemory>,
@ -201,59 +203,10 @@ impl InterpContext {
}
fn call_import(&mut self, name: &str, args: &[ConstVal]) -> Option<SmallVec<[ConstVal; 2]>> {
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()[..]);
}

63
src/interp/wasi.rs Normal file
View file

@ -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<SmallVec<[ConstVal; 2]>> {
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,
}
}