diff --git a/src/webassembly/instance.rs b/src/webassembly/instance.rs index b7f17e1bc..2603d9994 100644 --- a/src/webassembly/instance.rs +++ b/src/webassembly/instance.rs @@ -74,6 +74,81 @@ pub struct EmscriptenData { pub stack_alloc: extern "C" fn(u32, &Instance) -> u32, } +impl EmscriptenData { + pub fn new(module: &Module, instance: &Instance) -> Self { + unsafe { + debug!("emscripten::new"); + let malloc_export = module.info.exports.get("_malloc"); + let free_export = module.info.exports.get("_free"); + let memalign_export = module.info.exports.get("_memalign"); + let memset_export = module.info.exports.get("_memset"); + let stack_alloc_export = module.info.exports.get("stackAlloc"); + + let mut malloc_addr = 0 as *const u8; + let mut free_addr = 0 as *const u8; + let mut memalign_addr = 0 as *const u8; + let mut memset_addr = 0 as *const u8; + let mut stack_alloc_addr = 0 as _; + + if let Some(Export::Function(malloc_index)) = malloc_export { + malloc_addr = instance.get_function_pointer(*malloc_index); + } + + if let Some(Export::Function(free_index)) = free_export { + free_addr = instance.get_function_pointer(*free_index); + } + + if let Some(Export::Function(memalign_index)) = memalign_export { + memalign_addr = instance.get_function_pointer(*memalign_index); + } + + if let Some(Export::Function(memset_index)) = memset_export { + memset_addr = instance.get_function_pointer(*memset_index); + } + + if let Some(Export::Function(stack_alloc_index)) = stack_alloc_export { + stack_alloc_addr = instance.get_function_pointer(*stack_alloc_index); + } + + EmscriptenData { + malloc: mem::transmute(malloc_addr), + free: mem::transmute(free_addr), + memalign: mem::transmute(memalign_addr), + memset: mem::transmute(memset_addr), + stack_alloc: mem::transmute(stack_alloc_addr), + } + } + } + + // Emscripten __ATINIT__ + pub fn atinit(&self, module: &Module, instance: &Instance) -> Result<(), String> { + debug!("emscripten::atinit"); + if let Some(&Export::Function(environ_constructor_index)) = + module.info.exports.get("___emscripten_environ_constructor") + { + debug!("emscripten::___emscripten_environ_constructor"); + let ___emscripten_environ_constructor: extern "C" fn(&Instance) = + get_instance_function!(instance, environ_constructor_index); + call_protected!(___emscripten_environ_constructor(&instance)) + .map_err(|err| format!("{}", err))?; + }; + Ok(()) + // TODO: We also need to handle TTY.init() and SOCKFS.root = FS.mount(SOCKFS, {}, null) + } + + // Emscripten __ATEXIT__ + pub fn atexit(&self, module: &Module, instance: &Instance) -> Result<(), String> { + debug!("emscripten::atexit"); + use libc::fflush; + use std::ptr; + // Flush all open streams + unsafe { + fflush(ptr::null_mut()); + }; + Ok(()) + } +} + impl fmt::Debug for EmscriptenData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("EmscriptenData") @@ -554,66 +629,7 @@ impl Instance { tables: tables_pointer[..].into(), }; - let emscripten_data = if options.abi == InstanceABI::Emscripten { - unsafe { - debug!("emscripten::initiating data"); - let malloc_export = module.info.exports.get("_malloc"); - let free_export = module.info.exports.get("_free"); - let memalign_export = module.info.exports.get("_memalign"); - let memset_export = module.info.exports.get("_memset"); - let stack_alloc_export = module.info.exports.get("stackAlloc"); - - let mut malloc_addr = 0 as *const u8; - let mut free_addr = 0 as *const u8; - let mut memalign_addr = 0 as *const u8; - let mut memset_addr = 0 as *const u8; - let mut stack_alloc_addr = 0 as _; - - if malloc_export.is_none() - && free_export.is_none() - && memalign_export.is_none() - && memset_export.is_none() - { - None - } else { - if let Some(Export::Function(malloc_index)) = malloc_export { - malloc_addr = - get_function_addr(&malloc_index, &import_functions, &functions); - } - - if let Some(Export::Function(free_index)) = free_export { - free_addr = get_function_addr(&free_index, &import_functions, &functions); - } - - if let Some(Export::Function(memalign_index)) = memalign_export { - memalign_addr = - get_function_addr(&memalign_index, &import_functions, &functions); - } - - if let Some(Export::Function(memset_index)) = memset_export { - memset_addr = - get_function_addr(&memset_index, &import_functions, &functions); - } - - if let Some(Export::Function(stack_alloc_index)) = stack_alloc_export { - stack_alloc_addr = - get_function_addr(&stack_alloc_index, &import_functions, &functions); - } - - Some(EmscriptenData { - malloc: mem::transmute(malloc_addr), - free: mem::transmute(free_addr), - memalign: mem::transmute(memalign_addr), - memset: mem::transmute(memset_addr), - stack_alloc: mem::transmute(stack_alloc_addr), - }) - } - } - } else { - None - }; - - Ok(Instance { + let mut instance = Instance { data_pointers, tables: Arc::new(tables.into_iter().collect()), // tables.into_iter().map(|table| RwLock::new(table)).collect()), memories: Arc::new(memories.into_iter().collect()), @@ -621,8 +637,14 @@ impl Instance { functions, import_functions, start_func, - emscripten_data, - }) + emscripten_data: None, + }; + + if options.abi == InstanceABI::Emscripten { + instance.emscripten_data = Some(EmscriptenData::new(module, &instance)); + } + + Ok(instance) } pub fn memory_mut(&mut self, memory_index: usize) -> &mut LinearMemory { diff --git a/src/webassembly/mod.rs b/src/webassembly/mod.rs index d46d74030..2183c8f62 100644 --- a/src/webassembly/mod.rs +++ b/src/webassembly/mod.rs @@ -14,6 +14,7 @@ use cranelift_codegen::{ settings::{self, Configurable}, }; use cranelift_wasm::ModuleEnvironment; +use std::io::{self, Write}; use std::panic; use std::str::FromStr; use target_lexicon; @@ -153,7 +154,7 @@ pub fn get_isa() -> Box { isa::lookup(triple!("x86_64")).unwrap().finish(flags) } -fn store_module_arguments(path: &str, args: Vec<&str>, instance: &mut Instance) -> (u32, u32) { +fn store_module_arguments(path: &str, args: Vec<&str>, instance: &Instance) -> (u32, u32) { let argc = args.len() + 1; let (argv_offset, argv_slice): (_, &mut [u32]) = @@ -211,19 +212,9 @@ pub fn start_instance( path: &str, args: Vec<&str>, ) -> Result<(), String> { - if is_emscripten_module(&module) { - // Emscripten __ATINIT__ - if let Some(&Export::Function(environ_constructor_index)) = - module.info.exports.get("___emscripten_environ_constructor") - { - debug!("emscripten::___emscripten_environ_constructor"); - let ___emscripten_environ_constructor: extern "C" fn(&Instance) = - get_instance_function!(instance, environ_constructor_index); - call_protected!(___emscripten_environ_constructor(&instance)) - .map_err(|err| format!("{}", err))?; - }; + if let Some(ref emscripten_data) = &instance.emscripten_data { + emscripten_data.atinit(module, instance)?; - // TODO: We also need to handle TTY.init() and SOCKFS.root = FS.mount(SOCKFS, {}, null) let func_index = match module.info.exports.get("_main") { Some(&Export::Function(index)) => index, _ => panic!("_main emscripten function not found"), @@ -232,7 +223,7 @@ pub fn start_instance( let sig_index = module.get_func_type(func_index); let signature = module.get_signature(sig_index); let num_params = signature.params.len(); - match num_params { + let result = match num_params { 2 => { let main: extern "C" fn(u32, u32, &Instance) = get_instance_function!(instance, func_index); @@ -248,8 +239,11 @@ pub fn start_instance( num_params ), } - .map_err(|err| format!("{}", err)) - // TODO: We should implement emscripten __ATEXIT__ + .map_err(|err| format!("{}", err)); + + emscripten_data.atexit(module, instance)?; + + result } else { let func_index = instance