From b1ba24e99d5caf4c1deebb2b41dd7078fc31c34f Mon Sep 17 00:00:00 2001 From: Steve Akinyemi Date: Mon, 26 Nov 2018 22:01:15 +0100 Subject: [PATCH 1/5] Add _localtimeand _time functions --- src/apis/emscripten/env.rs | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/src/apis/emscripten/env.rs b/src/apis/emscripten/env.rs index 623de1191..97f91c2b6 100644 --- a/src/apis/emscripten/env.rs +++ b/src/apis/emscripten/env.rs @@ -6,6 +6,7 @@ use std::os::raw::c_char; use std::{slice, mem}; use crate::webassembly::Instance; +use super::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; /// emscripten: _getenv pub extern "C" fn _getenv(name_ptr: c_int, instance: &mut Instance) -> c_int { @@ -22,33 +23,6 @@ pub extern "C" fn _getenv(name_ptr: c_int, instance: &mut Instance) -> c_int { } } -unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 { - let s = CStr::from_ptr(cstr).to_str().unwrap(); - let space_offset = (instance.emscripten_data.malloc)(s.len() as _, instance); - let raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8; - let mut slice = slice::from_raw_parts_mut(raw_memory, s.len()); - - for (byte, loc) in s.bytes().zip(slice.iter_mut()) { - *loc = byte; - } - - space_offset -} - -unsafe fn copy_terminated_array_of_cstrs(instance: &mut Instance, cstrs: *mut *mut c_char) -> u32 { - let total_num = { - let mut ptr = cstrs; - let mut counter = 0; - while !(*ptr).is_null() { - counter += 1; - ptr = ptr.add(1); - } - counter - }; - println!("total_num: {}", total_num); - 0 -} - pub extern "C" fn _getpwnam(name_ptr: c_int, instance: &mut Instance) -> c_int { #[repr(C)] struct GuestPasswd { @@ -111,4 +85,4 @@ pub extern "C" fn _getgrnam(name_ptr: c_int, instance: &mut Instance) -> c_int { group_struct_offset as c_int } -} \ No newline at end of file +} From ec9e83eca6675167ec0b70cd874d1bec7c56b1eb Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 26 Nov 2018 15:42:47 -0500 Subject: [PATCH 2/5] Add a few more syscalls --- src/apis/emscripten/env.rs | 30 ++++++++++++++- src/apis/emscripten/mod.rs | 42 ++++++++++++++++---- src/apis/emscripten/time.rs | 77 +++++++++++++++++++++++++++++-------- 3 files changed, 123 insertions(+), 26 deletions(-) diff --git a/src/apis/emscripten/env.rs b/src/apis/emscripten/env.rs index 97f91c2b6..d8b433533 100644 --- a/src/apis/emscripten/env.rs +++ b/src/apis/emscripten/env.rs @@ -1,12 +1,21 @@ use super::super::host; /// NOTE: These syscalls only support wasm_32 for now because they take u32 offset -use libc::{c_int, getpwnam as libc_getpwnam, passwd, getgrnam as libc_getgrnam, group}; +use libc::{ + c_int, getpwnam as libc_getpwnam, passwd, + getgrnam as libc_getgrnam, group, clock_gettime as libc_clock_gettime, timespec, + // uname as libc_uname, utsname, +}; use std::ffi::CStr; use std::os::raw::c_char; use std::{slice, mem}; +use std::time::SystemTime; use crate::webassembly::Instance; +<<<<<<< HEAD use super::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; +======= +use crate::webassembly::LinearMemory; +>>>>>>> Add a few more syscalls /// emscripten: _getenv pub extern "C" fn _getenv(name_ptr: c_int, instance: &mut Instance) -> c_int { @@ -86,3 +95,22 @@ pub extern "C" fn _getgrnam(name_ptr: c_int, instance: &mut Instance) -> c_int { group_struct_offset as c_int } } + +pub extern fn _getpid(_instance: &mut Instance) -> c_int { + 0 +} +pub extern fn _getppid(_instance: &mut Instance) -> c_int { + 0 +} + +pub extern fn _uname(_buf: c_int, _instance: &mut Instance) -> c_int { + 0 +} + +pub extern fn _localtime_r() -> u32 { + 0 +} + +pub extern fn _getpagesize() -> u32 { + LinearMemory::PAGE_SIZE +} diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index b0495743a..7a24dd663 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -57,9 +57,9 @@ pub fn emscripten_set_up_memory(memory: &mut LinearMemory) { macro_rules! mock_external { ($import:ident, $name:ident) => {{ - fn _mocked_fn() { + fn _mocked_fn() -> i32 { println!("emscripten::{} ", stringify!($name)); - // return 0 + 0 } $import.set( "env", @@ -293,8 +293,34 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { import_object.set( "env", "_clock_gettime", - ImportValue::Func(time::_clock_gettime as _), + ImportValue::Func(env::_clock_gettime as _), ); + import_object.set( + "env", + "___syscall20", + ImportValue::Func(env::_getpid as _), + ); + import_object.set( + "env", + "___syscall64", + ImportValue::Func(env::_getppid as _), + ); + import_object.set( + "env", + "___syscall122", + ImportValue::Func(env::_uname as _), + ); + import_object.set( + "env", + "_localtime_r", + ImportValue::Func(env::_localtime_r as _), + ); + import_object.set( + "env", + "_getpagesize", + ImportValue::Func(env::_getpagesize as _), + ); + mock_external!(import_object, _waitpid); mock_external!(import_object, _utimes); mock_external!(import_object, _usleep); @@ -315,14 +341,14 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { mock_external!(import_object, _sched_yield); mock_external!(import_object, _raise); mock_external!(import_object, _mktime); - mock_external!(import_object, _localtime_r); + // mock_external!(import_object, _localtime_r); mock_external!(import_object, _localtime); mock_external!(import_object, _llvm_stacksave); mock_external!(import_object, _llvm_stackrestore); mock_external!(import_object, _kill); mock_external!(import_object, _gmtime_r); // mock_external!(import_object, _gettimeofday); - mock_external!(import_object, _getpagesize); + // mock_external!(import_object, _getpagesize); mock_external!(import_object, _getgrent); mock_external!(import_object, _getaddrinfo); mock_external!(import_object, _fork); @@ -335,7 +361,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { mock_external!(import_object, ___syscall85); mock_external!(import_object, ___syscall75); mock_external!(import_object, ___syscall66); - mock_external!(import_object, ___syscall64); + // mock_external!(import_object, ___syscall64); mock_external!(import_object, ___syscall63); mock_external!(import_object, ___syscall60); mock_external!(import_object, ___syscall54); @@ -364,9 +390,9 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { // mock_external!(import_object, ___syscall145); mock_external!(import_object, ___syscall142); mock_external!(import_object, ___syscall140); - mock_external!(import_object, ___syscall122); + // mock_external!(import_object, ___syscall122); mock_external!(import_object, ___syscall102); - mock_external!(import_object, ___syscall20); + // mock_external!(import_object, ___syscall20); mock_external!(import_object, ___syscall15); mock_external!(import_object, ___syscall10); diff --git a/src/apis/emscripten/time.rs b/src/apis/emscripten/time.rs index 85c9d7519..35fd37253 100644 --- a/src/apis/emscripten/time.rs +++ b/src/apis/emscripten/time.rs @@ -4,29 +4,72 @@ use std::ptr; use crate::webassembly::Instance; /// emscripten: _gettimeofday -pub extern "C" fn _gettimeofday(timeval_ptr_offset: c_int, tz_offset: c_int, instance: &mut Instance) -> c_int { - debug!("emscripten::_gettimeofday {}", timeval_ptr_offset); +// pub extern "C" fn _gettimeofday(timeval_ptr_offset: c_int, tz_offset: c_int, instance: &mut Instance) -> c_int { +// debug!("emscripten::_gettimeofday {}", timeval_ptr_offset); - unsafe { - let mut timeval_value = *(instance.memory_offset_addr(0, timeval_ptr_offset as _) as *mut timeval); - // We skip the timezone for now - let mut tz = ptr::null_mut(); - debug!("emscripten::_gettimeofday(initial) {} {}", (timeval_value).tv_sec, (timeval_value).tv_usec); +// unsafe { +// let mut timeval_value = *(instance.memory_offset_addr(0, timeval_ptr_offset as _) as *mut timeval); +// // We skip the timezone for now +// let mut tz = ptr::null_mut(); +// debug!("emscripten::_gettimeofday(initial) {} {}", (timeval_value).tv_sec, (timeval_value).tv_usec); - let returned = gettimeofday(&mut timeval_value, tz); - debug!("emscripten::_gettimeofday(filled) {} {}", (timeval_value).tv_sec, (timeval_value).tv_usec); - returned +// let returned = gettimeofday(&mut timeval_value, tz); +// debug!("emscripten::_gettimeofday(filled) {} {}", (timeval_value).tv_sec, (timeval_value).tv_usec); +// returned +// } +// } +pub extern fn _gettimeofday(tp: c_int, tz: c_int, instance: &mut Instance) -> c_int { + #[repr(C)] + struct GuestTimeVal { + tv_sec: i32, + tv_usec: i32, } + + assert!(tz == 0, "the timezone argument of `_gettimeofday` must be null"); + unsafe { + let now = SystemTime::now(); + let since_epoch = now.duration_since(SystemTime::UNIX_EPOCH).unwrap(); + let timeval_struct_ptr = instance.memory_offset_addr(0, tp as _) as *mut GuestTimeVal; + + (*timeval_struct_ptr).tv_sec = since_epoch.as_secs() as _; + (*timeval_struct_ptr).tv_usec = since_epoch.subsec_nanos() as _; + } + 0 } + /// emscripten: _clock_gettime -pub extern "C" fn _clock_gettime(clk_id: clockid_t, tp_offset: c_int, instance: &mut Instance) -> c_int { - debug!("emscripten::_clock_gettime {} {}", clk_id, tp_offset); +// pub extern "C" fn _clock_gettime(clk_id: clockid_t, tp_offset: c_int, instance: &mut Instance) -> c_int { +// debug!("emscripten::_clock_gettime {} {}", clk_id, tp_offset); + +// unsafe { +// let mut tp = instance.memory_offset_addr(0, tp_offset as _) as *mut timespec; +// let returned = clock_gettime(clk_id, tp); +// debug!("emscripten::clock_gettime(filled) {} {}", (*tp).tv_sec, (*tp).tv_nsec); +// returned +// } +// } + +pub extern fn _clock_gettime(clk_id: c_int, tp: c_int, instance: &mut Instance) -> c_int { + #[repr(C)] + struct GuestTimeSpec { + tv_sec: i32, + tv_nsec: i32, + } unsafe { - let mut tp = instance.memory_offset_addr(0, tp_offset as _) as *mut timespec; - let returned = clock_gettime(clk_id, tp); - debug!("emscripten::clock_gettime(filled) {} {}", (*tp).tv_sec, (*tp).tv_nsec); - returned + let mut timespec = timespec { + tv_sec: 0, + tv_nsec: 0, + }; + let ret = libc_clock_gettime(clk_id as _, &mut timespec); + if ret != 0 { + return ret; + } + + let timespec_struct_ptr = instance.memory_offset_addr(0, tp as _) as *mut GuestTimeSpec; + (*timespec_struct_ptr).tv_sec = timespec.tv_sec as _; + (*timespec_struct_ptr).tv_nsec = timespec.tv_nsec as _; } -} + 0 +} \ No newline at end of file From bd3b78ccc8452dc1b50f64b814abda9c2f4ad529 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 26 Nov 2018 16:06:27 -0500 Subject: [PATCH 3/5] Add several more syscalls --- src/apis/emscripten/env.rs | 5 ++++- src/apis/emscripten/memory.rs | 3 ++- src/apis/emscripten/mod.rs | 6 +++--- src/apis/emscripten/time.rs | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/apis/emscripten/env.rs b/src/apis/emscripten/env.rs index d8b433533..c3c9f6356 100644 --- a/src/apis/emscripten/env.rs +++ b/src/apis/emscripten/env.rs @@ -8,7 +8,6 @@ use libc::{ use std::ffi::CStr; use std::os::raw::c_char; use std::{slice, mem}; -use std::time::SystemTime; use crate::webassembly::Instance; <<<<<<< HEAD @@ -114,3 +113,7 @@ pub extern fn _localtime_r() -> u32 { pub extern fn _getpagesize() -> u32 { LinearMemory::PAGE_SIZE } + +pub extern fn _prlimit(pid: c_int, resource: c_int, new_limit: c_int, old_limit: c_int, instance: &mut Instance) -> c_int { + 0 +} diff --git a/src/apis/emscripten/memory.rs b/src/apis/emscripten/memory.rs index cbaa7e6bf..241fe462e 100644 --- a/src/apis/emscripten/memory.rs +++ b/src/apis/emscripten/memory.rs @@ -21,7 +21,8 @@ pub extern "C" fn _emscripten_memcpy_big( /// emscripten: getTotalMemory pub extern "C" fn get_total_memory(instance: &mut Instance) -> u32 { debug!("emscripten::get_total_memory"); - instance.memories[0].current_pages() + // instance.memories[0].current_pages() + 16777216 } /// emscripten: enlargeMemory diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index 7a24dd663..27aab3460 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -57,9 +57,9 @@ pub fn emscripten_set_up_memory(memory: &mut LinearMemory) { macro_rules! mock_external { ($import:ident, $name:ident) => {{ - fn _mocked_fn() -> i32 { + extern fn _mocked_fn() -> i32 { println!("emscripten::{} ", stringify!($name)); - 0 + -1 } $import.set( "env", @@ -293,7 +293,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { import_object.set( "env", "_clock_gettime", - ImportValue::Func(env::_clock_gettime as _), + ImportValue::Func(time::_clock_gettime as _), ); import_object.set( "env", diff --git a/src/apis/emscripten/time.rs b/src/apis/emscripten/time.rs index 35fd37253..296c99f36 100644 --- a/src/apis/emscripten/time.rs +++ b/src/apis/emscripten/time.rs @@ -1,5 +1,5 @@ -use libc::{gettimeofday, timeval, c_int, clock_gettime, clockid_t, timespec}; -use std::ptr; +use libc::{timeval, c_int, clock_gettime as libc_clock_gettime, timespec}; +use std::time::SystemTime; use crate::webassembly::Instance; From 3be1bdba30151774e1a00c54a72b6eec9e34c291 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Mon, 26 Nov 2018 16:11:01 -0500 Subject: [PATCH 4/5] Fix build errors --- src/apis/emscripten/env.rs | 3 --- src/apis/emscripten/utils.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/apis/emscripten/env.rs b/src/apis/emscripten/env.rs index c3c9f6356..e68bb9b65 100644 --- a/src/apis/emscripten/env.rs +++ b/src/apis/emscripten/env.rs @@ -10,11 +10,8 @@ use std::os::raw::c_char; use std::{slice, mem}; use crate::webassembly::Instance; -<<<<<<< HEAD use super::utils::{copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; -======= use crate::webassembly::LinearMemory; ->>>>>>> Add a few more syscalls /// emscripten: _getenv pub extern "C" fn _getenv(name_ptr: c_int, instance: &mut Instance) -> c_int { diff --git a/src/apis/emscripten/utils.rs b/src/apis/emscripten/utils.rs index bbc659a0c..70f78b2e0 100644 --- a/src/apis/emscripten/utils.rs +++ b/src/apis/emscripten/utils.rs @@ -1,4 +1,8 @@ use crate::webassembly::module::Module; +use crate::webassembly::Instance; +use std::ffi::CStr; +use std::os::raw::c_char; +use std::{slice, mem}; /// We check if a provided module is an Emscripten generated one pub fn is_emscripten_module(module: &Module) -> bool { @@ -10,6 +14,32 @@ pub fn is_emscripten_module(module: &Module) -> bool { return false; } +pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 { + let s = CStr::from_ptr(cstr).to_str().unwrap(); + let space_offset = (instance.emscripten_data.malloc)(s.len() as _, instance); + let raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8; + let mut slice = slice::from_raw_parts_mut(raw_memory, s.len()); + + for (byte, loc) in s.bytes().zip(slice.iter_mut()) { + *loc = byte; + } + space_offset +} + +pub unsafe fn copy_terminated_array_of_cstrs(instance: &mut Instance, cstrs: *mut *mut c_char) -> u32 { + let total_num = { + let mut ptr = cstrs; + let mut counter = 0; + while !(*ptr).is_null() { + counter += 1; + ptr = ptr.add(1); + } + counter + }; + println!("total_num: {}", total_num); + 0 +} + #[cfg(test)] mod tests { use super::super::generate_emscripten_env; From 3f819e3a79f8751f72c2a9ed7fe31580020fee7a Mon Sep 17 00:00:00 2001 From: Steve Akinyemi Date: Mon, 26 Nov 2018 22:15:49 +0100 Subject: [PATCH 5/5] Move some functions to utils --- src/apis/emscripten/mod.rs | 37 ++++++++++++++++++++++-------------- src/apis/emscripten/time.rs | 35 ++++++++++++++++++++++++++++++++-- src/apis/emscripten/utils.rs | 32 +++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/apis/emscripten/mod.rs b/src/apis/emscripten/mod.rs index b0495743a..c45df0896 100644 --- a/src/apis/emscripten/mod.rs +++ b/src/apis/emscripten/mod.rs @@ -133,6 +133,16 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "_getenv", ImportValue::Func(env::_getenv as *const u8), ); + import_object.set( + "env", + "_getpwnam", + ImportValue::Func(env::_getpwnam as _), + ); + import_object.set( + "env", + "_getgrnam", + ImportValue::Func(env::_getgrnam as _), + ); // Errno import_object.set( "env", @@ -273,18 +283,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "nullFunc_viiii", ImportValue::Func(nullfunc::nullfunc_viiii as *const u8), ); - - // named syscalls - import_object.set( - "env", - "_getpwnam", - ImportValue::Func(env::_getpwnam as _), - ); - import_object.set( - "env", - "_getgrnam", - ImportValue::Func(env::_getgrnam as _), - ); + // Time import_object.set( "env", "_gettimeofday", @@ -295,10 +294,20 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { "_clock_gettime", ImportValue::Func(time::_clock_gettime as _), ); + import_object.set( + "env", + "_localtime", + ImportValue::Func(time::_localtime as _), + ); + import_object.set( + "env", + "_time", + ImportValue::Func(time::_time as _), + ); mock_external!(import_object, _waitpid); mock_external!(import_object, _utimes); mock_external!(import_object, _usleep); - mock_external!(import_object, _time); + // mock_external!(import_object, _time); mock_external!(import_object, _sysconf); mock_external!(import_object, _strftime); mock_external!(import_object, _sigsuspend); @@ -316,7 +325,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> { mock_external!(import_object, _raise); mock_external!(import_object, _mktime); mock_external!(import_object, _localtime_r); - mock_external!(import_object, _localtime); + // mock_external!(import_object, _localtime); mock_external!(import_object, _llvm_stacksave); mock_external!(import_object, _llvm_stackrestore); mock_external!(import_object, _kill); diff --git a/src/apis/emscripten/time.rs b/src/apis/emscripten/time.rs index 85c9d7519..4c4d67ab7 100644 --- a/src/apis/emscripten/time.rs +++ b/src/apis/emscripten/time.rs @@ -1,5 +1,16 @@ -use libc::{gettimeofday, timeval, c_int, clock_gettime, clockid_t, timespec}; -use std::ptr; +use libc::{ + gettimeofday, + timeval, + c_int, + clock_gettime, + clockid_t, + timespec, + tm, + localtime, + time_t, + time +}; +use std::{ptr, slice, mem}; use crate::webassembly::Instance; @@ -30,3 +41,23 @@ pub extern "C" fn _clock_gettime(clk_id: clockid_t, tp_offset: c_int, instance: returned } } + +/// emscripten: _localtime +pub extern "C" fn _localtime(time_p: u32, instance: &mut Instance) -> *mut tm { + debug!("emscripten::_localtime {}", time_p); + + unsafe { + let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64; + localtime(time_p_addr) + } +} + +/// emscripten: _time +pub extern "C" fn _time(time_p: u32, instance: &mut Instance) -> time_t { + debug!("emscripten::_time {}", time_p); + + unsafe { + let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64; + time(time_p_addr) + } +} diff --git a/src/apis/emscripten/utils.rs b/src/apis/emscripten/utils.rs index bbc659a0c..4c2198160 100644 --- a/src/apis/emscripten/utils.rs +++ b/src/apis/emscripten/utils.rs @@ -1,4 +1,9 @@ use crate::webassembly::module::Module; +use std::ffi::CStr; +use std::os::raw::c_char; +use std::{slice, mem}; + +use crate::webassembly::Instance; /// We check if a provided module is an Emscripten generated one pub fn is_emscripten_module(module: &Module) -> bool { @@ -10,6 +15,33 @@ pub fn is_emscripten_module(module: &Module) -> bool { return false; } +pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 { + let s = CStr::from_ptr(cstr).to_str().unwrap(); + let space_offset = (instance.emscripten_data.malloc)(s.len() as _, instance); + let raw_memory = instance.memory_offset_addr(0, space_offset as _) as *mut u8; + let mut slice = slice::from_raw_parts_mut(raw_memory, s.len()); + + for (byte, loc) in s.bytes().zip(slice.iter_mut()) { + *loc = byte; + } + + space_offset +} + +pub unsafe fn copy_terminated_array_of_cstrs(instance: &mut Instance, cstrs: *mut *mut c_char) -> u32 { + let total_num = { + let mut ptr = cstrs; + let mut counter = 0; + while !(*ptr).is_null() { + counter += 1; + ptr = ptr.add(1); + } + counter + }; + println!("total_num: {}", total_num); + 0 +} + #[cfg(test)] mod tests { use super::super::generate_emscripten_env;