#[cfg(unix)] mod unix; #[cfg(windows)] mod windows; #[cfg(unix)] pub use self::unix::*; #[cfg(windows)] pub use self::windows::*; use crate::utils::{copy_stat_into_wasm, get_cstr_path, get_current_directory}; use super::varargs::VarArgs; use byteorder::{ByteOrder, LittleEndian}; /// NOTE: TODO: These syscalls only support wasm_32 for now because they assume offsets are u32 /// Syscall list: https://www.cs.utexas.edu/~bismith/test/syscalls/syscalls32.html use libc::{ // ENOTTY, c_int, c_void, chdir, // fcntl, setsockopt, getppid close, dup2, exit, fstat, getpid, // iovec, lseek, off_t, // open, read, rename, // sockaddr_in, // readv, rmdir, // writev, stat, write, // readlink, }; use wasmer_runtime_core::{ memory::ptr::{Array, WasmPtr}, vm::Ctx, }; use super::env; use std::cell::Cell; #[allow(unused_imports)] use std::io::Error; use std::mem; use std::slice; /// exit pub fn ___syscall1(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) { debug!("emscripten::___syscall1 (exit) {}", _which); let status: i32 = varargs.get(ctx); unsafe { exit(status); } } /// read pub fn ___syscall3(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { // -> ssize_t debug!("emscripten::___syscall3 (read) {}", _which); let fd: i32 = varargs.get(ctx); let buf: u32 = varargs.get(ctx); let count: i32 = varargs.get(ctx); debug!("=> fd: {}, buf_offset: {}, count: {}", fd, buf, count); let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *mut c_void; let ret = unsafe { read(fd, buf_addr, count as _) }; debug!("=> ret: {}", ret); ret as _ } /// write pub fn ___syscall4(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall4 (write) {}", _which); let fd: i32 = varargs.get(ctx); let buf: i32 = varargs.get(ctx); let count: i32 = varargs.get(ctx); debug!("=> fd: {}, buf: {}, count: {}", fd, buf, count); let buf_addr = emscripten_memory_pointer!(ctx.memory(0), buf) as *const c_void; unsafe { write(fd, buf_addr, count as _) as i32 } } /// close pub fn ___syscall6(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall6 (close) {}", _which); let fd: i32 = varargs.get(ctx); debug!("fd: {}", fd); unsafe { close(fd) } } // chdir pub fn ___syscall12(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall12 (chdir) {}", _which); let path_ptr = varargs.get_str(ctx); let real_path_owned = get_cstr_path(ctx, path_ptr); let real_path = if let Some(ref rp) = real_path_owned { rp.as_c_str().as_ptr() } else { path_ptr }; let ret = unsafe { chdir(real_path) }; debug!( "=> path: {:?}, ret: {}", unsafe { std::ffi::CStr::from_ptr(real_path) }, ret ); ret } pub fn ___syscall10(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall10"); -1 } pub fn ___syscall14(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall14"); -1 } pub fn ___syscall15(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall15"); -1 } // getpid pub fn ___syscall20(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall20 (getpid)"); unsafe { getpid() } } pub fn ___syscall21(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall21"); -1 } pub fn ___syscall25(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall25"); -1 } pub fn ___syscall29(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall29"); -1 } pub fn ___syscall32(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall32"); -1 } pub fn ___syscall33(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall33"); -1 } pub fn ___syscall36(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall36"); -1 } // rename pub fn ___syscall38(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall38 (rename)"); let old_path = varargs.get_str(ctx); let new_path = varargs.get_str(ctx); let real_old_path_owned = get_cstr_path(ctx, old_path); let real_old_path = if let Some(ref rp) = real_old_path_owned { rp.as_c_str().as_ptr() } else { old_path }; let real_new_path_owned = get_cstr_path(ctx, new_path); let real_new_path = if let Some(ref rp) = real_new_path_owned { rp.as_c_str().as_ptr() } else { new_path }; let result = unsafe { rename(real_old_path, real_new_path) }; debug!( "=> old_path: {}, new_path: {}, result: {}", unsafe { std::ffi::CStr::from_ptr(real_old_path).to_str().unwrap() }, unsafe { std::ffi::CStr::from_ptr(real_new_path).to_str().unwrap() }, result ); result } // rmdir pub fn ___syscall40(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall40 (rmdir)"); let pathname_addr = varargs.get_str(ctx); let real_path_owned = get_cstr_path(ctx, pathname_addr); let real_path = if let Some(ref rp) = real_path_owned { rp.as_c_str().as_ptr() } else { pathname_addr }; unsafe { rmdir(real_path) } } // pipe pub fn ___syscall42(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall42 (pipe)"); // offset to a file descriptor, which contains a read end and write end, 2 integers let fd_offset: u32 = varargs.get(ctx); let emscripten_memory = ctx.memory(0); // convert the file descriptor into a vec with two slots let mut fd_vec: Vec = emscripten_memory.view()[((fd_offset / 4) as usize)..] .iter() .map(|pipe_end: &Cell| pipe_end.get()) .take(2) .collect(); // get it as a mutable pointer let fd_ptr = fd_vec.as_mut_ptr(); // call pipe and store the pointers in this array #[cfg(target_os = "windows")] let result: c_int = unsafe { libc::pipe(fd_ptr, 2048, 0) }; #[cfg(not(target_os = "windows"))] let result: c_int = unsafe { libc::pipe(fd_ptr) }; result } pub fn ___syscall51(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall51"); -1 } pub fn ___syscall52(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall52"); -1 } pub fn ___syscall53(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall53"); -1 } pub fn ___syscall60(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall60"); -1 } // dup2 pub fn ___syscall63(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall63 (dup2) {}", _which); let src: i32 = varargs.get(ctx); let dst: i32 = varargs.get(ctx); unsafe { dup2(src, dst) } } // getppid pub fn ___syscall64(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall64 (getppid)"); unsafe { getpid() } } pub fn ___syscall66(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall66"); -1 } pub fn ___syscall75(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall75"); -1 } // readlink pub fn ___syscall85(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall85 (readlink)"); let _path = varargs.get_str(ctx); let buf = varargs.get_str(ctx); // let buf_addr: i32 = varargs.get(ctx); let buf_size: i32 = varargs.get(ctx); let fd = 3; let ret = unsafe { read(fd, buf as _, buf_size as _) as i32 }; debug!( "=> buf: {}, buf_size: {}, return: {} ", unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() }, buf_size, ret ); // let ret = unsafe { // readlink(path, buf as _, buf_size as _) as i32 // }; // debug!("=> path: {}, buf: {}, buf_size: {}, return: {} ", // unsafe { std::ffi::CStr::from_ptr(path).to_str().unwrap() }, // unsafe { std::ffi::CStr::from_ptr(buf as _).to_str().unwrap() }, // // std::ffi::CStr::from_ptr(buf).to_str().unwrap(), // // buf, // buf_size, // ret); ret } pub fn ___syscall91(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall91 - stub"); 0 } pub fn ___syscall96(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall96"); -1 } pub fn ___syscall97(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall97"); -1 } pub fn ___syscall110(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall110"); -1 } pub fn ___syscall121(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall121"); -1 } pub fn ___syscall125(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall125"); -1 } pub fn ___syscall132(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall132"); -1 } pub fn ___syscall133(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall133"); -1 } pub fn ___syscall144(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall144"); -1 } pub fn ___syscall147(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall147"); -1 } pub fn ___syscall150(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall150"); -1 } pub fn ___syscall151(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall151"); -1 } pub fn ___syscall152(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall152"); -1 } pub fn ___syscall153(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall153"); -1 } pub fn ___syscall163(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall163"); -1 } // getcwd pub fn ___syscall183(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { debug!("emscripten::___syscall183"); let buf_offset: WasmPtr = varargs.get(ctx); let _size: c_int = varargs.get(ctx); let path = get_current_directory(ctx); let path_string = path.unwrap().display().to_string(); let len = path_string.len(); let buf_writer = buf_offset.deref(ctx.memory(0), 0, len as u32 + 1).unwrap(); for (i, byte) in path_string.bytes().enumerate() { buf_writer[i].set(byte as i8); } buf_writer[len].set(0); buf_offset.offset() as i32 } // mmap2 pub fn ___syscall192(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall192 (mmap2) {}", _which); let _addr: i32 = varargs.get(ctx); let len: u32 = varargs.get(ctx); let _prot: i32 = varargs.get(ctx); let _flags: i32 = varargs.get(ctx); let fd: i32 = varargs.get(ctx); let _off: i32 = varargs.get(ctx); debug!( "=> addr: {}, len: {}, prot: {}, flags: {}, fd: {}, off: {}", _addr, len, _prot, _flags, fd, _off ); if fd == -1 { let ptr = env::call_memalign(ctx, 16384, len); if ptr == 0 { // ENOMEM return -12; } let real_ptr = emscripten_memory_pointer!(ctx.memory(0), ptr) as *const u8; env::call_memset(ctx, ptr, 0, len); for i in 0..(len as usize) { unsafe { assert_eq!(*real_ptr.add(i), 0); } } debug!("=> ptr: {}", ptr); return ptr as i32; } else { // return ENODEV return -19; } } /// lseek pub fn ___syscall140(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { // -> c_int debug!("emscripten::___syscall140 (lseek) {}", _which); let fd: i32 = varargs.get(ctx); let _ = varargs.get::(ctx); // ignore high offset let offset_low: i32 = varargs.get(ctx); let result_ptr_value = varargs.get::(ctx); let whence: i32 = varargs.get(ctx); let offset = offset_low as off_t; let ret = unsafe { lseek(fd, offset, whence) as i32 }; #[allow(clippy::cast_ptr_alignment)] let result_ptr = emscripten_memory_pointer!(ctx.memory(0), result_ptr_value) as *mut i32; assert_eq!(8, mem::align_of_val(&result_ptr)); unsafe { *result_ptr = ret; } debug!( "=> fd: {}, offset: {}, result_ptr: {}, whence: {} = {}\nlast os error: {}", fd, offset, result_ptr_value, whence, 0, Error::last_os_error(), ); 0 } /// readv #[allow(clippy::cast_ptr_alignment)] pub fn ___syscall145(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> i32 { // -> ssize_t debug!("emscripten::___syscall145 (readv) {}", _which); let fd: i32 = varargs.get(ctx); let iov: i32 = varargs.get(ctx); let iovcnt: i32 = varargs.get(ctx); #[repr(C)] struct GuestIovec { iov_base: i32, iov_len: i32, } debug!("=> fd: {}, iov: {}, iovcnt = {}", fd, iov, iovcnt); let mut ret = 0; unsafe { for i in 0..iovcnt { let guest_iov_addr = emscripten_memory_pointer!(ctx.memory(0), (iov + i * 8)) as *mut GuestIovec; let iov_base = emscripten_memory_pointer!(ctx.memory(0), (*guest_iov_addr).iov_base) as *mut c_void; let iov_len = (*guest_iov_addr).iov_len as _; // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); let curr = read(fd, iov_base, iov_len); if curr < 0 { return -1; } ret += curr; } // debug!(" => ret: {}", ret); ret as _ } } // writev #[allow(clippy::cast_ptr_alignment)] pub fn ___syscall146(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { // -> ssize_t debug!("emscripten::___syscall146 (writev) {}", _which); let fd: i32 = varargs.get(ctx); let iov: i32 = varargs.get(ctx); let iovcnt: i32 = varargs.get(ctx); #[repr(C)] struct GuestIovec { iov_base: i32, iov_len: i32, } debug!("=> fd: {}, iov: {}, iovcnt = {}", fd, iov, iovcnt); let mut ret = 0; unsafe { for i in 0..iovcnt { let guest_iov_addr = emscripten_memory_pointer!(ctx.memory(0), (iov + i * 8)) as *mut GuestIovec; let iov_base = emscripten_memory_pointer!(ctx.memory(0), (*guest_iov_addr).iov_base) as *const c_void; let iov_len = (*guest_iov_addr).iov_len as _; // debug!("=> iov_addr: {:?}, {:?}", iov_base, iov_len); let curr = write(fd, iov_base, iov_len); if curr < 0 { return -1; } ret += curr; } // debug!(" => ret: {}", ret); ret as _ } } pub fn ___syscall168(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall168 - stub"); -1 } pub fn ___syscall191(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let _resource: i32 = varargs.get(ctx); debug!( "emscripten::___syscall191 - mostly stub, resource: {}", _resource ); let rlim_emptr: i32 = varargs.get(ctx); let rlim_ptr = emscripten_memory_pointer!(ctx.memory(0), rlim_emptr) as *mut u8; let rlim = unsafe { slice::from_raw_parts_mut(rlim_ptr, 16) }; // set all to RLIM_INIFINTY LittleEndian::write_i64(&mut rlim[..], -1); LittleEndian::write_i64(&mut rlim[8..], -1); 0 } pub fn ___syscall193(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall193"); -1 } // stat64 pub fn ___syscall195(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall195 (stat64) {}", _which); let pathname_addr = varargs.get_str(ctx); let buf: u32 = varargs.get(ctx); let real_path_owned = get_cstr_path(ctx, pathname_addr); let real_path = if let Some(ref rp) = real_path_owned { rp.as_c_str().as_ptr() } else { pathname_addr }; unsafe { let mut _stat: stat = std::mem::zeroed(); let ret = stat(real_path, &mut _stat); debug!( "=> pathname: {}, buf: {} = {}, last os error: {}", std::ffi::CStr::from_ptr(real_path).to_str().unwrap(), buf, ret, Error::last_os_error() ); if ret != 0 { return ret; } copy_stat_into_wasm(ctx, buf, &_stat); } 0 } // fstat64 pub fn ___syscall197(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall197 (fstat64) {}", _which); let fd: c_int = varargs.get(ctx); let buf: u32 = varargs.get(ctx); unsafe { let mut stat = std::mem::zeroed(); let ret = fstat(fd, &mut stat); debug!("ret: {}", ret); if ret != 0 { return ret; } copy_stat_into_wasm(ctx, buf, &stat); } 0 } pub fn ___syscall199(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall199 - stub"); -1 } pub fn ___syscall209(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall209"); -1 } pub fn ___syscall211(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall211"); -1 } pub fn ___syscall218(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall218"); -1 } // fcntl64 pub fn ___syscall221(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall221 (fcntl64) {}", _which); // fcntl64 let _fd: i32 = varargs.get(ctx); let cmd: u32 = varargs.get(ctx); // (FAPPEND - 0x08 // |FASYNC - 0x40 // |FFSYNC - 0x80 // |FNONBLOCK - 0x04 debug!("=> fd: {}, cmd: {}", _fd, cmd); match cmd { 1 | 2 => 0, 13 | 14 => 0, // pretend file locking worked _ => -1, } } pub fn ___syscall268(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall268"); -1 } pub fn ___syscall269(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall269"); -1 } pub fn ___syscall272(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall272"); -1 } pub fn ___syscall295(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall295"); -1 } pub fn ___syscall296(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall296"); -1 } pub fn ___syscall297(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall297"); -1 } pub fn ___syscall298(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall298"); -1 } pub fn ___syscall300(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall300"); -1 } pub fn ___syscall301(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall301"); -1 } pub fn ___syscall302(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall302"); -1 } pub fn ___syscall303(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall303"); -1 } pub fn ___syscall304(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall304"); -1 } pub fn ___syscall305(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall305"); -1 } pub fn ___syscall306(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall306"); -1 } pub fn ___syscall307(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall307"); -1 } pub fn ___syscall308(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall308"); -1 } // utimensat pub fn ___syscall320(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall320 (utimensat), {}", _which); 0 } pub fn ___syscall331(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall331"); -1 } pub fn ___syscall333(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall333"); -1 } pub fn ___syscall334(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall334"); -1 } pub fn ___syscall337(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall337"); -1 } // prlimit64 pub fn ___syscall340(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_int { debug!("emscripten::___syscall340 (prlimit64), {}", _which); // NOTE: Doesn't really matter. Wasm modules cannot exceed WASM_PAGE_SIZE anyway. let _pid: i32 = varargs.get(ctx); let resource: i32 = varargs.get(ctx); let _new_limit: u32 = varargs.get(ctx); let old_limit: u32 = varargs.get(ctx); let val = match resource { // RLIMIT_NOFILE 7 => 1024, _ => -1, // RLIM_INFINITY }; if old_limit != 0 { // just report no limits let buf_ptr = emscripten_memory_pointer!(ctx.memory(0), old_limit) as *mut u8; let buf = unsafe { slice::from_raw_parts_mut(buf_ptr, 16) }; LittleEndian::write_i64(&mut buf[..], val); LittleEndian::write_i64(&mut buf[8..], val); } 0 } pub fn ___syscall345(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall345"); -1 }