Add a bunch of required functions and syscalls

This commit is contained in:
Steve Akinyemi 2018-12-13 19:28:30 +01:00
parent 2c2d21044f
commit 7f91a64cf6
11 changed files with 364 additions and 133 deletions

View File

@ -0,0 +1,14 @@
use crate::webassembly::Instance;
/// emscripten: ___cxa_allocate_exception
pub extern "C" fn ___cxa_allocate_exception(size: u32, instance: &mut Instance) -> u32 {
debug!("emscripten::___cxa_allocate_exception");
(instance.emscripten_data.as_ref().unwrap().malloc)(size as _, instance)
}
/// emscripten: ___cxa_throw
/// TODO: We don't have support for exceptions yet
pub extern "C" fn ___cxa_throw(ptr: u32, ty: u32, destructor: u32, instance: &mut Instance) {
debug!("emscripten::___cxa_throw");
debug!("unimplmeneted yet!");
}

View File

@ -10,3 +10,8 @@ pub extern "C" fn ___lock(_which: c_int, _varargs: c_int, _instance: &mut Instan
pub extern "C" fn ___unlock(_which: c_int, _varargs: c_int, _instance: &mut Instance) {
debug!("emscripten::___unlock");
}
// NOTE: Not implemented by Emscripten
pub extern "C" fn ___wait(_which: c_int, _varargs: c_int, _instance: &mut Instance) {
debug!("emscripten::___wait");
}

View File

@ -0,0 +1,19 @@
use crate::webassembly::Instance;
/// emscripten: _llvm_log10_f64
pub extern "C" fn _llvm_log10_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_log10_f64");
value.log10()
}
/// emscripten: _llvm_log2_f64
pub extern "C" fn _llvm_log2_f64(value: f64) -> f64 {
debug!("emscripten::_llvm_log2_f64");
value.log2()
}
// emscripten: f64-rem
pub extern "C" fn f64_rem(x: f64, y: f64) -> f64 {
debug!("emscripten::f64-rem");
x % y
}

View File

@ -1,6 +1,6 @@
use super::process::abort_with_message;
use crate::webassembly::Instance;
use libc::{c_void, memcpy, size_t};
use libc::{c_void, memcpy, size_t, c_int};
/// emscripten: _emscripten_memcpy_big
pub extern "C" fn _emscripten_memcpy_big(
@ -36,3 +36,11 @@ pub extern "C" fn abort_on_cannot_grow_memory() {
debug!("emscripten::abort_on_cannot_grow_memory");
abort_with_message("Cannot enlarge memory arrays!");
}
/// emscripten: ___map_file
pub extern "C" fn ___map_file() -> c_int {
debug!("emscripten::___map_file");
// NOTE: TODO: Em returns -1 here as well. May need to implement properly
-1
}

View File

@ -9,6 +9,8 @@ mod errno;
mod io;
mod lock;
mod memory;
mod math;
mod exception;
mod nullfunc;
mod process;
mod signal;
@ -99,6 +101,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
// Lock
import_object.set("env", "___lock", ImportValue::Func(lock::___lock as _));
import_object.set("env", "___unlock", ImportValue::Func(lock::___unlock as _));
import_object.set("env", "___wait", ImportValue::Func(lock::___wait as _));
// Env
import_object.set("env", "_getenv", ImportValue::Func(env::_getenv as _));
import_object.set("env", "_getpwnam", ImportValue::Func(env::_getpwnam as _));
@ -136,16 +139,71 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"___syscall6",
ImportValue::Func(syscalls::___syscall6 as _),
);
import_object.set(
"env",
"___syscall12",
ImportValue::Func(syscalls::___syscall12 as _),
);
import_object.set(
"env",
"___syscall20",
ImportValue::Func(syscalls::___syscall20 as _),
);
import_object.set(
"env",
"___syscall39",
ImportValue::Func(syscalls::___syscall39 as _),
);
import_object.set(
"env",
"___syscall40",
ImportValue::Func(syscalls::___syscall40 as _),
);
import_object.set(
"env",
"___syscall54",
ImportValue::Func(syscalls::___syscall54 as _),
);
import_object.set(
"env",
"___syscall57",
ImportValue::Func(syscalls::___syscall57 as _),
);
import_object.set(
"env",
"___syscall63",
ImportValue::Func(syscalls::___syscall63 as _),
);
import_object.set(
"env",
"___syscall64",
ImportValue::Func(syscalls::___syscall64 as _),
);
import_object.set(
"env",
"___syscall102",
ImportValue::Func(syscalls::___syscall102 as _),
);
import_object.set(
"env",
"___syscall114",
ImportValue::Func(syscalls::___syscall114 as _),
);
import_object.set(
"env",
"___syscall122",
ImportValue::Func(syscalls::___syscall122 as _),
);
import_object.set(
"env",
"___syscall140",
ImportValue::Func(syscalls::___syscall140 as _),
);
import_object.set(
"env",
"___syscall142",
ImportValue::Func(syscalls::___syscall142 as _),
);
import_object.set(
"env",
"___syscall145",
@ -158,23 +216,28 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
);
import_object.set(
"env",
"___syscall221",
ImportValue::Func(syscalls::___syscall221 as _),
"___syscall180",
ImportValue::Func(syscalls::___syscall180 as _),
);
import_object.set(
"env",
"___syscall20",
ImportValue::Func(syscalls::___syscall20 as _),
"___syscall181",
ImportValue::Func(syscalls::___syscall181 as _),
);
import_object.set(
"env",
"___syscall64",
ImportValue::Func(syscalls::___syscall64 as _),
"___syscall192",
ImportValue::Func(syscalls::___syscall192 as _),
);
import_object.set(
"env",
"___syscall122",
ImportValue::Func(syscalls::___syscall122 as _),
"___syscall195",
ImportValue::Func(syscalls::___syscall195 as _),
);
import_object.set(
"env",
"___syscall197",
ImportValue::Func(syscalls::___syscall197 as _),
);
import_object.set(
"env",
@ -186,36 +249,6 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"___syscall202",
ImportValue::Func(syscalls::___syscall202 as _),
);
import_object.set(
"env",
"___syscall340",
ImportValue::Func(syscalls::___syscall340 as _),
);
import_object.set(
"env",
"___syscall197",
ImportValue::Func(syscalls::___syscall197 as _),
);
import_object.set(
"env",
"___syscall180",
ImportValue::Func(syscalls::___syscall180 as _),
);
import_object.set(
"env",
"___syscall181",
ImportValue::Func(syscalls::___syscall181 as _),
);
import_object.set(
"env",
"___syscall39",
ImportValue::Func(syscalls::___syscall39 as _),
);
import_object.set(
"env",
"___syscall195",
ImportValue::Func(syscalls::___syscall195 as _),
);
import_object.set(
"env",
"___syscall212",
@ -228,40 +261,14 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
);
import_object.set(
"env",
"___syscall102",
ImportValue::Func(syscalls::___syscall102 as _),
"___syscall330",
ImportValue::Func(syscalls::___syscall330 as _),
);
import_object.set(
"env",
"___syscall54",
ImportValue::Func(syscalls::___syscall54 as _),
"___syscall340",
ImportValue::Func(syscalls::___syscall340 as _),
);
import_object.set(
"env",
"___syscall12",
ImportValue::Func(syscalls::___syscall12 as _),
);
import_object.set(
"env",
"___syscall192",
ImportValue::Func(syscalls::___syscall192 as _),
);
import_object.set(
"env",
"___syscall63",
ImportValue::Func(syscalls::___syscall63 as _),
);
import_object.set(
"env",
"___syscall142",
ImportValue::Func(syscalls::___syscall142 as _),
);
import_object.set(
"env",
"___syscall57",
ImportValue::Func(syscalls::___syscall57 as _),
);
// Process
import_object.set("env", "abort", ImportValue::Func(process::em_abort as _));
import_object.set("env", "_abort", ImportValue::Func(process::_abort as _));
@ -270,9 +277,15 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"abortStackOverflow",
ImportValue::Func(process::abort_stack_overflow as _),
);
import_object.set(
"env",
"_llvm_trap",
ImportValue::Func(process::_llvm_trap as _),
);
import_object.set("env", "_fork", ImportValue::Func(process::_fork as _));
import_object.set("env", "_exit", ImportValue::Func(process::_exit as _));
import_object.set("env", "_system", ImportValue::Func(process::_system as _));
import_object.set("env", "_popen", ImportValue::Func(process::_popen as _));
// Signal
import_object.set(
"env",
@ -320,6 +333,22 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"getTotalMemory",
ImportValue::Func(memory::get_total_memory as _),
);
import_object.set(
"env",
"___map_file",
ImportValue::Func(memory::___map_file as _),
);
// Exception
import_object.set(
"env",
"___cxa_allocate_exception",
ImportValue::Func(exception::___cxa_allocate_exception as _),
);
import_object.set(
"env",
"___cxa_allocate_exception",
ImportValue::Func(exception::___cxa_throw as _),
);
// NullFuncs
import_object.set(
"env",
@ -366,6 +395,16 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"nullFunc_viiii",
ImportValue::Func(nullfunc::nullfunc_viiii as _),
);
import_object.set(
"env",
"nullFunc_viiiii",
ImportValue::Func(nullfunc::nullfunc_viiiii as _),
);
import_object.set(
"env",
"nullFunc_viiiiii",
ImportValue::Func(nullfunc::nullfunc_viiiiii as _),
);
// Time
import_object.set(
"env",
@ -377,6 +416,21 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"_clock_gettime",
ImportValue::Func(time::_clock_gettime as _),
);
import_object.set(
"env",
"___clock_gettime",
ImportValue::Func(time::___clock_gettime as _),
);
import_object.set(
"env",
"_clock",
ImportValue::Func(time::_clock as _),
);
import_object.set(
"env",
"_difftime",
ImportValue::Func(time::_difftime as _),
);
import_object.set(
"env",
"_asctime",
@ -409,6 +463,11 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
"_sysconf",
ImportValue::Func(env::_sysconf as _),
);
// Math
import_object.set("env", "_llvm_log10_f64", ImportValue::Func(math::_llvm_log10_f64 as _));
import_object.set("env", "_llvm_log2_f64", ImportValue::Func(math::_llvm_log2_f64 as _));
import_object.set("asm2wasm", "f64-rem", ImportValue::Func(math::f64_rem as _));
mock_external!(import_object, _waitpid);
mock_external!(import_object, _utimes);

View File

@ -45,3 +45,13 @@ pub extern "C" fn nullfunc_viiii(_x: u32, _instance: &Instance) {
debug!("emscripten::nullfunc_viiii");
abort_with_message("Invalid function pointer called with signature 'viiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub extern "C" fn nullfunc_viiiii(_x: u32, _instance: &Instance) {
debug!("emscripten::nullfunc_viiiii");
abort_with_message("Invalid function pointer called with signature 'viiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}
pub extern "C" fn nullfunc_viiiiii(_x: u32, _instance: &Instance) {
debug!("emscripten::nullfunc_viiiiii");
abort_with_message("Invalid function pointer called with signature 'viiiiii'. Perhaps this is an invalid value (e.g. caused by calling a virtual method on a NULL pointer)? Or calling a function with an incorrect type, which will fail? (it is worth building your source files with -Werror (warnings are errors), as warnings can indicate undefined behavior which can cause this)");
}

View File

@ -1,4 +1,4 @@
use libc::{abort, c_char, pid_t, c_int, exit};
use libc::{abort, c_char, pid_t, c_int, exit, EAGAIN};
use crate::webassembly::Instance;
use std::ffi::CStr;
@ -48,3 +48,22 @@ pub extern "C" fn abort_stack_overflow() {
// TODO: Message incomplete. Need to finish em runtime data first
abort_with_message("Stack overflow! Attempted to allocate some bytes on the stack");
}
pub extern "C" fn _llvm_trap() {
debug!("emscripten::_llvm_trap");
abort_with_message("abort!");
}
pub extern "C" fn _system() -> c_int {
debug!("emscripten::_system");
// TODO: May need to change this Em impl to a working version
eprintln!("Can't call external programs");
return EAGAIN;
}
pub extern "C" fn _popen() -> c_int {
debug!("emscripten::_popen");
// TODO: May need to change this Em impl to a working version
eprintln!("Missing function: popen");
unsafe { abort(); }
}

View File

@ -63,9 +63,21 @@ use libc::{
SOL_SOCKET,
TIOCGWINSZ,
// ENOTTY,
c_char
c_char,
rusage,
rmdir,
EINVAL,
fcntl,
F_SETFD,
F_GETFD,
};
// use std::sys::fd::FileDesc;
// Linking to functions that are provided by rust libc
#[cfg(target_os = "macos")]
#[link(name = "c")]
extern {
pub fn wait4(pid: pid_t, status: *mut c_int, options: c_int, rusage: *mut rusage) -> pid_t;
}
// Another conditional constant for name resolution: Macos et iOS use
// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
@ -181,15 +193,19 @@ pub extern "C" fn ___syscall39(
let pathname: u32 = varargs.get(instance);
let mode: u32 = varargs.get(instance);
let pathname_addr = instance.memory_offset_addr(0, pathname as usize) as *const i8;
unsafe { mkdir(pathname_addr, mode as _) };
0
unsafe { mkdir(pathname_addr, mode as _) }
}
// getppid
pub extern "C" fn ___syscall64() -> pid_t {
debug!("emscripten::___syscall64 (getppid)");
unsafe { getpid() }
// rmdir
pub extern "C" fn ___syscall40(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall40 (rmdir)");
let pathname: u32 = varargs.get(instance);
let pathname_addr = instance.memory_offset_addr(0, pathname as usize) as *const i8;
unsafe { rmdir(pathname_addr) }
}
/// ioctl
@ -234,6 +250,40 @@ pub extern "C" fn ___syscall54(
}
}
// setpgid
pub extern "C" fn ___syscall57(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall57 (setpgid)");
let pid: i32 = varargs.get(instance);
let pgid: i32 = varargs.get(instance);
unsafe {
setpgid(pid, pgid)
}
}
// dup2
pub extern "C" fn ___syscall63(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall63 (dup2)");
let src: i32 = varargs.get(instance);
let dst: i32 = varargs.get(instance);
unsafe { dup2(src, dst) }
}
// getppid
pub extern "C" fn ___syscall64() -> pid_t {
debug!("emscripten::___syscall64 (getppid)");
unsafe { getpid() }
}
// socketcall
pub extern "C" fn ___syscall102(
_which: c_int,
@ -365,7 +415,7 @@ pub extern "C" fn ___syscall102(
let fd = unsafe { accept(socket, address, address_len_addr) };
unsafe {
unsafe {
let address_linux = instance.memory_offset_addr(0, address_addr as usize) as *mut LinuxSockAddr;
(*address_linux).sa_family = (*address).sa_family as u16;
(*address_linux).sa_data = (*address).sa_data;
@ -503,6 +553,27 @@ pub extern "C" fn ___syscall102(
}
}
/// wait4
pub extern "C" fn ___syscall114(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> pid_t {
debug!("emscripten::___syscall114 (wait4)");
let pid: pid_t = varargs.get(instance);
let status: u32 = varargs.get(instance);
let options: c_int = varargs.get(instance);
let rusage: u32 = varargs.get(instance);
let status_addr = instance.memory_offset_addr(0, status as usize) as *mut c_int;
let rusage_addr = instance.memory_offset_addr(0, rusage as usize) as *mut rusage;
let res = unsafe { wait4(pid, status_addr, options, rusage_addr) };
debug!(
"=> pid: {}, status: {:?}, options: {}, rusage: {:?} = pid: {}",
pid, status_addr, options, rusage_addr, res
);
res
}
/// uname
// NOTE: Wondering if we should return custom utsname, like Emscripten.
pub extern "C" fn ___syscall122(
@ -517,6 +588,29 @@ pub extern "C" fn ___syscall122(
unsafe { uname(buf_addr) }
}
// select
pub extern "C" fn ___syscall142(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall142 (newselect)");
let nfds: i32 = varargs.get(instance);
let readfds: u32 = varargs.get(instance);
let writefds: u32 = varargs.get(instance);
let exceptfds: u32 = varargs.get(instance);
let _timeout: i32 = varargs.get(instance);
assert!(nfds <= 64, "`nfds` must be less than or equal to 64");
assert!(exceptfds == 0, "`exceptfds` is not supporrted");
let readfds_ptr = instance.memory_offset_addr(0, readfds as _) as _;
let writefds_ptr = instance.memory_offset_addr(0, writefds as _) as _;
unsafe { select(nfds, readfds_ptr, writefds_ptr, 0 as _, 0 as _) }
}
// mmap2
pub extern "C" fn ___syscall192(
_which: c_int,
@ -798,6 +892,42 @@ pub extern "C" fn ___syscall221(
}
}
/// dup3
pub extern "C" fn ___syscall330(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> pid_t {
// Implementation based on description at https://linux.die.net/man/2/dup3
debug!("emscripten::___syscall330 (dup3)");
let oldfd: c_int = varargs.get(instance);
let newfd: c_int = varargs.get(instance);
let flags: c_int = varargs.get(instance);
if oldfd == newfd {
return EINVAL;
}
let res = unsafe { dup2(oldfd, newfd) };
// Set flags on newfd (https://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html)
let mut old_flags = unsafe { fcntl (newfd, F_GETFD, 0) };
if old_flags > 0 {
old_flags |= flags;
} else if old_flags == 0 {
old_flags &= !flags;
}
unsafe { fcntl (newfd, F_SETFD, old_flags); }
debug!(
"=> oldfd: {}, newfd: {}, flags: {} = pid: {}",
oldfd, newfd, flags, res
);
res
}
// prlimit64
pub extern "C" fn ___syscall340(
_which: c_int,
@ -824,54 +954,3 @@ pub extern "C" fn ___syscall340(
0
}
// dup2
pub extern "C" fn ___syscall63(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall63 (dup2)");
let src: i32 = varargs.get(instance);
let dst: i32 = varargs.get(instance);
unsafe { dup2(src, dst) }
}
// select
pub extern "C" fn ___syscall142(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall142 (newselect)");
let nfds: i32 = varargs.get(instance);
let readfds: u32 = varargs.get(instance);
let writefds: u32 = varargs.get(instance);
let exceptfds: u32 = varargs.get(instance);
let _timeout: i32 = varargs.get(instance);
assert!(nfds <= 64, "`nfds` must be less than or equal to 64");
assert!(exceptfds == 0, "`exceptfds` is not supporrted");
let readfds_ptr = instance.memory_offset_addr(0, readfds as _) as _;
let writefds_ptr = instance.memory_offset_addr(0, writefds as _) as _;
unsafe { select(nfds, readfds_ptr, writefds_ptr, 0 as _, 0 as _) }
}
// setpgid
pub extern "C" fn ___syscall57(
_which: c_int,
mut varargs: VarArgs,
instance: &mut Instance,
) -> c_int {
debug!("emscripten::___syscall57 (setpgid)");
let pid: i32 = varargs.get(instance);
let pgid: i32 = varargs.get(instance);
unsafe {
setpgid(pid, pgid)
}
}

View File

@ -66,6 +66,24 @@ pub extern "C" fn _clock_gettime(clk_id: c_int, tp: c_int, instance: &mut Instan
0
}
/// emscripten: ___clock_gettime
pub extern "C" fn ___clock_gettime(clk_id: c_int, tp: c_int, instance: &mut Instance) -> c_int {
debug!("emscripten::___clock_gettime {} {}", clk_id, tp);
_clock_gettime(clk_id, tp, instance)
}
/// emscripten: _clock
pub extern "C" fn _clock() -> c_int {
debug!("emscripten::_clock");
0 // TODO: unimplemented
}
/// emscripten: _difftime
pub extern "C" fn _difftime(t0: u32, t1: u32) -> c_int {
debug!("emscripten::_difftime");
(t0 - t1) as _
}
#[repr(C)]
struct guest_tm {
pub tm_sec: c_int, // 0

View File

@ -17,7 +17,7 @@ pub fn is_emscripten_module(module: &Module) -> bool {
false
}
pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, instance: &Instance) -> u32 {
pub fn write_to_buf(string: *const c_char, buf: u32, max: u32, instance: &Instance) -> u32 {
let buf_addr = instance.memory_offset_addr(0, buf as _) as *mut c_char;
unsafe {

0
src/emtests/syscalls.rs Normal file
View File