diff --git a/.gitignore b/.gitignore index 3704b59..66c2f34 100644 --- a/.gitignore +++ b/.gitignore @@ -110,4 +110,8 @@ obj-intel64/* VERSION examples/w2c -examples/tests \ No newline at end of file +examples/tests + +# release +SHA* +elfconv-v* \ No newline at end of file diff --git a/README.md b/README.md index bec154f..1e6bf02 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ and elfconv uses [emscripten](https://github.com/emscripten-core/emscripten) (fo - Furthermore, a part of aarch64 instructions are not supported. if the instruction of your ELF binary is not supported, elfconv outputs the message (\[WARNING\] Unsupported instruction at 0x...) - No support of stripped binaries - No support of shared objects -- a lot of Linux system calls are unimplemented(ref: [`runtime/Syscall.cpp`](https://github.com/yomaytk/elfconv/blob/main/runtime/Syscall.cpp)) +- a lot of Linux system calls are unimplemented(ref: [`runtime/syscalls`](https://github.com/yomaytk/elfconv/blob/main/runtime/syscalls)) ## Quick Start You can try elfconv using docker container (amd64 and arm64) by executing the commands as follows. In default settings, both `elflift` (used for generating LLVM bitcode file) and `libelfconv.a` (used for executing generated LLVM bitcode) are installed to `~/.elfconv`. diff --git a/bin/elfconv.sh b/bin/elfconv.sh index ba2dbd6..fc08d8c 100755 --- a/bin/elfconv.sh +++ b/bin/elfconv.sh @@ -12,7 +12,7 @@ setting() { EMAR=emar OPTFLAGS="-O3" EMCCFLAGS="${OPTFLAGS} -I${ROOT_DIR}/backend/remill/include -I${ROOT_DIR}" - ELFCONV_MACROS="-DELFCONV_BROWSER_ENV=1" + ELFCONV_MACROS="-DELFC_BROWSER_ENV=1" ELFCONV_DEBUG_MACROS= ELFPATH=$( realpath "$1" ) WASMCC=$EMCC @@ -39,17 +39,19 @@ main() { fi # build runtime + SYSCALLCPP="syscall/SyscallBrowser.cpp" echo -e "[\033[32mINFO\033[0m] Building elfconv-Runtime ..." if [ "$TARGET" = "wasm-host" ]; then WASMCC=$WASISDKCXX WASMCCFLAGS=$WASISDKFLAGS WASMAR=$WASISDKAR + SYSCALLCPP="syscall/SyscallWasi.cpp" fi cd "${RUNTIME_DIR}" || { echo "cd Failure"; exit 1; } # shellcheck disable=SC2086 $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Entry.o -c Entry.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Memory.o -c Memory.cpp && \ - $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Syscall.o -c Syscall.cpp && \ + $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Syscall.o -c $SYSCALLCPP && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o VmIntrinsics.o -c VmIntrinsics.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Util.o -c "${UTILS_DIR}"/Util.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o elfconv.o -c "${UTILS_DIR}"/elfconv.cpp && \ diff --git a/release/elfconv.sh b/release/elfconv.sh index 94799db..8e3f429 100755 --- a/release/elfconv.sh +++ b/release/elfconv.sh @@ -5,7 +5,7 @@ setting() { WASMCC=emcc WASISDKCXX=${WASI_SDK_PATH}/bin/clang++ OPTFLAGS="-O3" - ELFCONV_MACROS="-DELFCONV_BROWSER_ENV=1" + ELFCONV_MACROS="-DELFC_BROWSER_ENV=1" ELFPATH=$( realpath "$1" ) BITCODEPATH=$( realpath "$2" ) diff --git a/release/prepare.sh b/release/prepare.sh index b919e6f..e721c11 100755 --- a/release/prepare.sh +++ b/release/prepare.sh @@ -16,7 +16,7 @@ setting() { EMCXX=emcc EMAR=emar EMCCFLAGS="${OPTFLAGS} -I${ELFCONV_DIR}/backend/remill/include -I${ELFCONV_DIR}" - EMCC_ELFCONV_MACROS="-DELFCONV_BROWSER_ENV=1" + EMCC_ELFCONV_MACROS="-DELFC_BROWSER_ENV=1" # wasi-sdk WASISDKCXX=${WASI_SDK_PATH}/bin/clang++ @@ -62,7 +62,7 @@ main() { # shellcheck disable=SC2086 $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o Entry.o -c Entry.cpp && \ $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o Memory.o -c Memory.cpp && \ - $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o Syscall.o -c Syscall.cpp && \ + $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o Syscall.o -c syscalls/SyscallBrowser.cpp && \ $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o VmIntrinsics.o -c VmIntrinsics.cpp && \ $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o Util.o -c "${UTILS_DIR}"/Util.cpp && \ $EMCXX $EMCCFLAGS $EMCC_ELFCONV_MACROS -o elfconv.o -c "${UTILS_DIR}"/elfconv.cpp && \ @@ -80,7 +80,7 @@ main() { # shellcheck disable=SC2086 $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o Entry.o -c Entry.cpp && \ $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o Memory.o -c Memory.cpp && \ - $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o Syscall.o -c Syscall.cpp && \ + $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o Syscall.o -c syscalls/SyscallWasi.cpp && \ $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o VmIntrinsics.o -c VmIntrinsics.cpp && \ $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o Util.o -c "${UTILS_DIR}"/Util.cpp && \ $WASISDKCXX $WASISDKFLAGS $WASI_ELFCONV_MACROS -o elfconv.o -c "${UTILS_DIR}"/elfconv.cpp && \ diff --git a/runtime/Memory.h b/runtime/Memory.h index 508c7a3..35c3234 100644 --- a/runtime/Memory.h +++ b/runtime/Memory.h @@ -20,7 +20,9 @@ class MappedMemory; class RuntimeManager; /* own implementation of syscall emulation */ -extern void __svc_call(); +extern void __svc_native_call(); +extern void __svc_browser_call(); +extern void __svc_wasi_call(); /* translate the address of the original ELF to the actual address of mapped space */ extern void *_ecv_translate_ptr(addr_t vma_addr); extern "C" uint64_t *__g_get_indirectbr_block_address(uint64_t fun_vma, uint64_t bb_vma); diff --git a/runtime/VmIntrinsics.cpp b/runtime/VmIntrinsics.cpp index 4ba90a2..553ddf4 100644 --- a/runtime/VmIntrinsics.cpp +++ b/runtime/VmIntrinsics.cpp @@ -88,7 +88,13 @@ Memory *__remill_write_memory_f128(Memory *, addr_t, float128_t) { */ Memory *__remill_syscall_tranpoline_call(State &state, Memory *memory) { /* TODO: We should select one syscall emulate process (own implementation, WASI, LKL, etc...) */ - __svc_call(); +#if defined(ELFC_WASI_ENV) + __svc_wasi_call(); +#elif defined(ELFC_BROWSER_ENV) + __svc_browser_call(); +#else + __svc_native_call(); +#endif return nullptr; } diff --git a/runtime/syscalls/SysTable.h b/runtime/syscalls/SysTable.h new file mode 100644 index 0000000..918f8ee --- /dev/null +++ b/runtime/syscalls/SysTable.h @@ -0,0 +1,41 @@ +#pragma once + +#define _ECV_EACCESS 13 +#define _ECV_ENOSYS 38 +/* + syscall number table +*/ +#define AARCH64_SYS_IOCTL 29 +#define AARCH64_SYS_FACCESSAT 48 +#define AARCH64_SYS_OPENAT 56 +#define AARCH64_SYS_CLOSE 57 +#define AARCH64_SYS_READ 63 +#define AARCH64_SYS_WRITE 64 +#define AARCH64_SYS_WRITEV 66 +#define AARCH64_SYS_READLINKAT 78 +#define AARCH64_SYS_NEWFSTATAT 79 +#define AARCH64_SYS_EXIT 93 +#define AARCH64_SYS_EXITGROUP 94 +#define AARCH64_SYS_SET_TID_ADDRESS 96 +#define AARCH64_SYS_FUTEX 98 +#define AARCH64_SYS_SET_ROBUST_LIST 99 +#define AARCH64_SYS_CLOCK_GETTIME 113 +#define AARCH64_SYS_TGKILL 131 +#define AARCH64_SYS_RT_SIGACTION 134 +#define AARCH64_SYS_RT_SIGPROCMASK 135 +#define AARCH64_SYS_UNAME 160 +#define AARCH64_SYS_GETPID 172 +#define AARCH64_SYS_GETPPID 173 +#define AARCH64_SYS_GETTUID 174 +#define AARCH64_SYS_GETEUID 175 +#define AARCH64_SYS_GETGID 176 +#define AARCH64_SYS_GETEGID 177 +#define AARCH64_SYS_GETTID 178 +#define AARCH64_SYS_BRK 214 +#define AARCH64_SYS_MUNMAP 215 +#define AARCH64_SYS_MMAP 222 +#define AARCH64_SYS_MPROTECT 226 +#define AARCH64_SYS_PRLIMIT64 261 +#define AARCH64_SYS_GETRANDOM 278 +#define AARCH64_SYS_STATX 291 +#define AARCH64_SYS_RSEQ 293 \ No newline at end of file diff --git a/runtime/Syscall.cpp b/runtime/syscalls/SyscallBrowser.cpp similarity index 78% rename from runtime/Syscall.cpp rename to runtime/syscalls/SyscallBrowser.cpp index 0858f09..30281d8 100644 --- a/runtime/Syscall.cpp +++ b/runtime/syscalls/SyscallBrowser.cpp @@ -1,4 +1,5 @@ -#include "Memory.h" +#include "SysTable.h" +#include "runtime/Memory.h" #include #include @@ -6,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -13,10 +15,7 @@ #include #include #include -#if !defined(ELFC_WASI_ENV) -# include -# include -#endif +#include #include #include #include @@ -30,47 +29,6 @@ # define NOP_SYSCALL(sysnum) ; #endif -/* - syscall number table -*/ -#define AARCH64_SYS_IOCTL 29 -#define AARCH64_SYS_FACCESSAT 48 -#define AARCH64_SYS_OPENAT 56 -#define AARCH64_SYS_CLOSE 57 -#define AARCH64_SYS_READ 63 -#define AARCH64_SYS_WRITE 64 -#define AARCH64_SYS_WRITEV 66 -#define AARCH64_SYS_READLINKAT 78 -#define AARCH64_SYS_NEWFSTATAT 79 -#define AARCH64_SYS_EXIT 93 -#define AARCH64_SYS_EXITGROUP 94 -#define AARCH64_SYS_SET_TID_ADDRESS 96 -#define AARCH64_SYS_FUTEX 98 -#define AARCH64_SYS_SET_ROBUST_LIST 99 -#define AARCH64_SYS_CLOCK_GETTIME 113 -#define AARCH64_SYS_TGKILL 131 -#define AARCH64_SYS_RT_SIGACTION 134 -#define AARCH64_SYS_RT_SIGPROCMASK 135 -#define AARCH64_SYS_UNAME 160 -#define AARCH64_SYS_GETPID 172 -#define AARCH64_SYS_GETPPID 173 -#define AARCH64_SYS_GETTUID 174 -#define AARCH64_SYS_GETEUID 175 -#define AARCH64_SYS_GETGID 176 -#define AARCH64_SYS_GETEGID 177 -#define AARCH64_SYS_GETTID 178 -#define AARCH64_SYS_BRK 214 -#define AARCH64_SYS_MUNMAP 215 -#define AARCH64_SYS_MMAP 222 -#define AARCH64_SYS_MPROTECT 226 -#define AARCH64_SYS_PRLIMIT64 261 -#define AARCH64_SYS_GETRANDOM 278 -#define AARCH64_SYS_STATX 291 -#define AARCH64_SYS_RSEQ 293 - -#define _ECV_EACCESS 13 -#define _ECV_ENOSYS 38 - /* for ioctl syscall */ @@ -130,7 +88,7 @@ struct _ecv_statx { arch: arm64, syscall NR: x8, return: x0, arg0: x0, arg1: x1, arg2: x2, arg3: x3, arg4: x4, arg5: x5 ref: https://blog.xhyeax.com/2022/04/28/arm64-syscall-table/ */ -void __svc_call(void) { +void __svc_browser_call(void) { auto &state_gpr = g_state.gpr; errno = 0; @@ -140,12 +98,6 @@ void __svc_call(void) { #endif switch (state_gpr.x8.qword) { case AARCH64_SYS_IOCTL: /* ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) */ -#if defined(ELFC_WASI_ENV) - EMPTY_SYSCALL(AARCH64_SYS_IOCTL) - state_gpr.x0.qword = -1; - errno = _ECV_EACCESS; - break; -#else { unsigned int fd = state_gpr.x0.dword; unsigned int cmd = state_gpr.x1.dword; @@ -172,7 +124,6 @@ void __svc_call(void) { default: break; } } -#endif case AARCH64_SYS_FACCESSAT: /* faccessat (int dfd, const char *filename, int mode) */ /* TODO */ state_gpr.x0.qword = -1; @@ -180,11 +131,6 @@ void __svc_call(void) { errno = _ECV_EACCESS; break; case AARCH64_SYS_OPENAT: /* openat (int dfd, const char* filename, int flags, umode_t mode) */ -#if defined(ELFC_WASI_ENV) - if (-100 == state_gpr.x0.dword) - state_gpr.x0.qword = AT_FDCWD; // AT_FDCWD on WASI: -2 (-100 on Linux) - state_gpr.x2.dword = O_RDWR; -#endif state_gpr.x0.dword = openat( state_gpr.x0.dword, (char *) _ecv_translate_ptr(state_gpr.x1.qword), state_gpr.x2.dword); if (-1 == state_gpr.x0.dword) @@ -228,19 +174,11 @@ void __svc_call(void) { break; case AARCH64_SYS_EXIT: /* exit (int error_code) */ exit(state_gpr.x0.dword); break; case AARCH64_SYS_EXITGROUP: /* exit_group (int error_code) note. there is no function of 'exit_group', so must use syscall. */ -#if defined(__linux__) - syscall(AARCH64_SYS_EXITGROUP, state_gpr.x0.dword); -#else exit(state_gpr.x0.dword); -#endif break; case AARCH64_SYS_SET_TID_ADDRESS: /* set_tid_address(int *tidptr) */ { -#if defined(ELFC_WASI_ENV) - pid_t tid = 42; -#else pid_t tid = gettid(); -#endif *reinterpret_cast(_ecv_translate_ptr(state_gpr.x0.qword)) = tid; state_gpr.x0.qword = tid; } break; @@ -260,12 +198,6 @@ void __svc_call(void) { errno = _ECV_EACCESS; break; case AARCH64_SYS_CLOCK_GETTIME: /* clock_gettime (clockid_t which_clock, struct __kernel_timespace *tp) */ -#if defined(ELFC_WASI_ENV) - EMPTY_SYSCALL(AARCH64_SYS_CLOCK_GETTIME); - state_gpr.x0.qword = -1; - errno = _ECV_EACCESS; - break; -#else { clockid_t which_clock = state_gpr.x0.dword; struct timespec emu_tp; @@ -273,17 +205,8 @@ void __svc_call(void) { memcpy(_ecv_translate_ptr(state_gpr.x1.qword), &emu_tp, sizeof(timespec)); state_gpr.x0.qword = (_ecv_reg64_t) clock_time; } break; -#endif case AARCH64_SYS_TGKILL: /* tgkill (pid_t tgid, pid_t pid, int sig) */ -#if defined(ELFC_WASI_ENV) - EMPTY_SYSCALL(AARCH64_SYS_TGKILL); - state_gpr.x0.qword = -1; - errno = _ECV_EACCESS; -#elif defined(__wasm__) state_gpr.x0.qword = kill(state_gpr.x0.dword, state_gpr.x1.dword); -#elif defined(__linux__) - state_gpr.x0.qword = tgkill(state_gpr.x0.dword, state_gpr.x1.dword, state_gpr.x2.dword); -#endif break; case AARCH64_SYS_RT_SIGPROCMASK: /* rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize) */ /* TODO */ @@ -291,26 +214,11 @@ void __svc_call(void) { EMPTY_SYSCALL(AARCH64_SYS_RT_SIGPROCMASK); break; case AARCH64_SYS_RT_SIGACTION: /* rt_sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) */ -#if defined(ELFC_WASI_ENV) - state_gpr.x0.qword = -1; - errno = _ECV_EACCESS; - EMPTY_SYSCALL(AARCH64_SYS_RT_SIGACTION) - break; -#else state_gpr.x0.dword = sigaction( state_gpr.x0.dword, (const struct sigaction *) _ecv_translate_ptr(state_gpr.x1.qword), (struct sigaction *) _ecv_translate_ptr(state_gpr.x2.qword)); break; -#endif case AARCH64_SYS_UNAME: /* uname (struct old_utsname* buf) */ -#if defined(__linux__) - { - struct utsname _utsname; - int ret = uname(&_utsname); - memcpy(_ecv_translate_ptr(state_gpr.x0.qword), &_utsname, sizeof(utsname)); - state_gpr.x0.dword = ret; - } -#else { struct __my_utsname { char sysname[65]; @@ -323,18 +231,7 @@ void __svc_call(void) { "#0~elfconv", "aarch64"}; memcpy(_ecv_translate_ptr(state_gpr.x0.qword), &new_utsname, sizeof(new_utsname)); state_gpr.x0.dword = 0; - } -#endif - break; -#if defined(ELFC_WASI_ENV) - case AARCH64_SYS_GETPID: /* getpid () */ state_gpr.x0.dword = 42; break; - case AARCH64_SYS_GETPPID: /* getppid () */ state_gpr.x0.dword = 42; break; - case AARCH64_SYS_GETTUID: /* getuid () */ state_gpr.x0.dword = 42; break; - case AARCH64_SYS_GETEUID: /* geteuid () */ state_gpr.x0.dword = 42; break; - case AARCH64_SYS_GETGID: /* getgid () */ state_gpr.x0.dword = 42; break; - case AARCH64_SYS_GETEGID: /* getegid () */ state_gpr.x0.dword = 42; break; - case AARCH64_SYS_GETTID: /* getttid () */ state_gpr.x0.dword = 42; break; -#else + } break; case AARCH64_SYS_GETPID: /* getpid () */ state_gpr.x0.dword = getpid(); break; case AARCH64_SYS_GETPPID: /* getppid () */ state_gpr.x0.dword = getppid(); break; case AARCH64_SYS_GETTUID: /* getuid () */ state_gpr.x0.dword = getuid(); break; @@ -342,7 +239,6 @@ void __svc_call(void) { case AARCH64_SYS_GETGID: /* getgid () */ state_gpr.x0.dword = getgid(); break; case AARCH64_SYS_GETEGID: /* getegid () */ state_gpr.x0.dword = getegid(); break; case AARCH64_SYS_GETTID: /* getttid () */ state_gpr.x0.dword = gettid(); break; -#endif case AARCH64_SYS_BRK: /* brk (unsigned long brk) */ { auto heap_memory = g_run_mgr->heap_memory; @@ -389,14 +285,9 @@ void __svc_call(void) { break; case AARCH64_SYS_GETRANDOM: /* getrandom (char *buf, size_t count, unsigned int flags) */ { -#if defined(ELFC_WASI_ENV) - memset(_ecv_translate_ptr(state_gpr.x0.qword), 1, static_cast(state_gpr.x1.qword)); - state_gpr.x0.qword = state_gpr.x1.qword; -#else auto res = getentropy(_ecv_translate_ptr(state_gpr.x0.qword), static_cast(state_gpr.x1.qword)); state_gpr.x0.qword = 0 == res ? state_gpr.x1.qword : -1; -#endif } break; case AARCH64_SYS_STATX: /* statx (int dfd, const char *path, unsigned flags, unsigned mask, struct statx *buffer) */ { @@ -406,12 +297,7 @@ void __svc_call(void) { elfconv_runtime_error("[ERROR] Unsupported statx(flags=0x%08u)\n", flags); struct stat _stat; // execute fstat -#if defined(ELFC_WASI_ENV) - errno = _ECV_EACCESS; - EMPTY_SYSCALL(AARCH64_SYS_STATX); -#else errno = fstat(dfd, &_stat); -#endif if (errno == 0) { struct _ecv_statx _statx; memset(&_statx, 0, sizeof(_statx)); diff --git a/runtime/syscalls/SyscallNative.cpp b/runtime/syscalls/SyscallNative.cpp new file mode 100644 index 0000000..2662a1b --- /dev/null +++ b/runtime/syscalls/SyscallNative.cpp @@ -0,0 +1,326 @@ +#include "SysTable.h" +#include "runtime/Memory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(ELFC_RUNTIME_SYSCALL_DEBUG) +# define EMPTY_SYSCALL(sysnum) printf("[WARNING] syscall \"" #sysnum "\" is empty now.\n"); +# define NOP_SYSCALL(sysnum) \ + printf("[INFO] syscall \"" #sysnum "\" is nop (but maybe allowd) now.\n"); +#else +# define EMPTY_SYSCALL(sysnum) ; +# define NOP_SYSCALL(sysnum) ; +#endif + +#define _ECV_EACCESS 13 +#define _ECV_ENOSYS 38 + +/* + for ioctl syscall +*/ +#define _ECV_TCGETS 0x5401 +#define _ECV_NCCS 19 +typedef uint32_t _ecv_tcflag_t; +typedef uint8_t _ecv_cc_t; +struct _ecv_termios { + _ecv_tcflag_t c_iflag; + _ecv_tcflag_t c_oflag; + _ecv_tcflag_t c_cflag; + _ecv_tcflag_t c_lflag; + _ecv_cc_t c_line; + _ecv_cc_t c_cc[_ECV_NCCS]; +}; + +/* + for statx +*/ +struct _ecv_statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; +}; +struct _ecv_statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct _ecv_statx_timestamp stx_atime; + struct _ecv_statx_timestamp stx_btime; + struct _ecv_statx_timestamp stx_ctime; + struct _ecv_statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t stx_mnt_id; + uint32_t stx_dio_mem_align; + uint32_t stx_dio_offset_align; + uint64_t __spare3[12]; +}; + +#define _ECV_AT_EMPTY_PATH 0x1000 +#define _ECV_STATX_BASIC_STATS 0x000007ffU + +/* + syscall emulate function + + Calling Conventions + arch: arm64, syscall NR: x8, return: x0, arg0: x0, arg1: x1, arg2: x2, arg3: x3, arg4: x4, arg5: x5 + ref: https://blog.xhyeax.com/2022/04/28/arm64-syscall-table/ +*/ +void __svc_native_call(void) { + + auto &state_gpr = g_state.gpr; + errno = 0; +#if defined(ELFC_RUNTIME_SYSCALL_DEBUG) + printf("[INFO] __svc_call started. syscall number: %u, PC: 0x%016llx\n", g_state.gpr.x8.dword, + g_state.gpr.pc.qword); +#endif + switch (state_gpr.x8.qword) { + case AARCH64_SYS_IOCTL: /* ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) */ + { + unsigned int fd = state_gpr.x0.dword; + unsigned int cmd = state_gpr.x1.dword; + unsigned long arg = state_gpr.x2.qword; + switch (cmd) { + case _ECV_TCGETS: { + struct termios t_host; + int rc = tcgetattr(fd, &t_host); + if (rc == 0) { + struct _ecv_termios t; + memset(&t, 0, sizeof(_ecv_termios)); + t.c_iflag = t_host.c_iflag; + t.c_oflag = t_host.c_oflag; + t.c_cflag = t_host.c_cflag; + t.c_lflag = t_host.c_lflag; + memcpy(t.c_cc, t_host.c_cc, std::min(NCCS, _ECV_NCCS)); + memcpy(_ecv_translate_ptr(arg), &t, sizeof(_ecv_termios)); + state_gpr.x0.qword = 0; + } else { + state_gpr.x0.qword = -1; + } + break; + } + default: break; + } + } + case AARCH64_SYS_FACCESSAT: /* faccessat (int dfd, const char *filename, int mode) */ + /* TODO */ + state_gpr.x0.qword = -1; + EMPTY_SYSCALL(AARCH64_SYS_FACCESSAT); + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_OPENAT: /* openat (int dfd, const char* filename, int flags, umode_t mode) */ + state_gpr.x0.dword = openat( + state_gpr.x0.dword, (char *) _ecv_translate_ptr(state_gpr.x1.qword), state_gpr.x2.dword); + if (-1 == state_gpr.x0.dword) + perror("openat error!"); + break; + case AARCH64_SYS_CLOSE: /* int close (unsigned int fd) */ + state_gpr.x0.dword = close(state_gpr.x0.dword); + break; + case AARCH64_SYS_READ: /* read (unsigned int fd, char *buf, size_t count) */ + state_gpr.x0.qword = read(state_gpr.x0.dword, (char *) _ecv_translate_ptr(state_gpr.x1.qword), + static_cast(state_gpr.x2.qword)); + break; + case AARCH64_SYS_WRITE: /* write (unsigned int fd, const char *buf, size_t count) */ + state_gpr.x0.qword = write(state_gpr.x0.dword, _ecv_translate_ptr(state_gpr.x1.qword), + static_cast(state_gpr.x2.qword)); + break; + case AARCH64_SYS_WRITEV: /* writev (unsgined long fd, const struct iovec *vec, unsigned long vlen) */ + { + unsigned long fd = state_gpr.x0.qword; + unsigned long vlen = state_gpr.x2.qword; + auto tr_vec = reinterpret_cast(_ecv_translate_ptr(state_gpr.x1.qword)); + auto cache_vec = reinterpret_cast(malloc(sizeof(iovec) * vlen)); + // translate every iov_base + for (unsigned long i = 0; i < vlen; i++) { + cache_vec[i].iov_base = _ecv_translate_ptr(reinterpret_cast(tr_vec[i].iov_base)); + cache_vec[i].iov_len = tr_vec[i].iov_len; + } + state_gpr.x0.qword = writev(fd, cache_vec, vlen); + free(cache_vec); + } break; + case AARCH64_SYS_READLINKAT: /* readlinkat (int dfd, const char *path, char *buf, int bufsiz) */ + state_gpr.x0.qword = + readlinkat(state_gpr.x0.dword, (const char *) _ecv_translate_ptr(state_gpr.x1.qword), + (char *) _ecv_translate_ptr(state_gpr.x2.qword), state_gpr.x3.dword); + break; + case AARCH64_SYS_NEWFSTATAT: /* newfstatat (int dfd, const char *filename, struct stat *statbuf, int flag) */ + /* TODO */ + state_gpr.x0.qword = -1; + EMPTY_SYSCALL(AARCH64_SYS_NEWFSTATAT); + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_EXIT: /* exit (int error_code) */ exit(state_gpr.x0.dword); break; + case AARCH64_SYS_EXITGROUP: /* exit_group (int error_code) note. there is no function of 'exit_group', so must use syscall. */ + syscall(AARCH64_SYS_EXITGROUP, state_gpr.x0.dword); + break; + case AARCH64_SYS_SET_TID_ADDRESS: /* set_tid_address(int *tidptr) */ + { + pid_t tid = gettid(); + *reinterpret_cast(_ecv_translate_ptr(state_gpr.x0.qword)) = tid; + state_gpr.x0.qword = tid; + } break; + case AARCH64_SYS_FUTEX: /* futex (u32 *uaddr, int op, u32 val, const struct __kernel_timespec *utime, u32 *uaddr2, u23 val3) */ + /* TODO */ + if ((state_gpr.x1.dword & 0x7F) == 0) { + /* FUTEX_WAIT */ + state_gpr.x0.qword = 0; + } else { + elfconv_runtime_error("Unknown futex op 0x%08u\n", state_gpr.x1.dword); + } + NOP_SYSCALL(AARCH64_SYS_FUTEX); + break; + case AARCH64_SYS_SET_ROBUST_LIST: /* set_robust_list (struct robust_list_head *head, size_t len) */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_SET_ROBUST_LIST); + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_CLOCK_GETTIME: /* clock_gettime (clockid_t which_clock, struct __kernel_timespace *tp) */ + { + clockid_t which_clock = state_gpr.x0.dword; + struct timespec emu_tp; + int clock_time = clock_gettime(which_clock, &emu_tp); + memcpy(_ecv_translate_ptr(state_gpr.x1.qword), &emu_tp, sizeof(timespec)); + state_gpr.x0.qword = (_ecv_reg64_t) clock_time; + } break; + case AARCH64_SYS_TGKILL: /* tgkill (pid_t tgid, pid_t pid, int sig) */ + state_gpr.x0.qword = tgkill(state_gpr.x0.dword, state_gpr.x1.dword, state_gpr.x2.dword); + break; + case AARCH64_SYS_RT_SIGPROCMASK: /* rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize) */ + /* TODO */ + state_gpr.x0.qword = 0; + EMPTY_SYSCALL(AARCH64_SYS_RT_SIGPROCMASK); + break; + case AARCH64_SYS_RT_SIGACTION: /* rt_sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) */ + state_gpr.x0.dword = sigaction( + state_gpr.x0.dword, (const struct sigaction *) _ecv_translate_ptr(state_gpr.x1.qword), + (struct sigaction *) _ecv_translate_ptr(state_gpr.x2.qword)); + break; + case AARCH64_SYS_UNAME: /* uname (struct old_utsname* buf) */ + { + struct utsname _utsname; + int ret = uname(&_utsname); + memcpy(_ecv_translate_ptr(state_gpr.x0.qword), &_utsname, sizeof(utsname)); + state_gpr.x0.dword = ret; + } break; + case AARCH64_SYS_GETPID: /* getpid () */ state_gpr.x0.dword = getpid(); break; + case AARCH64_SYS_GETPPID: /* getppid () */ state_gpr.x0.dword = getppid(); break; + case AARCH64_SYS_GETTUID: /* getuid () */ state_gpr.x0.dword = getuid(); break; + case AARCH64_SYS_GETEUID: /* geteuid () */ state_gpr.x0.dword = geteuid(); break; + case AARCH64_SYS_GETGID: /* getgid () */ state_gpr.x0.dword = getgid(); break; + case AARCH64_SYS_GETEGID: /* getegid () */ state_gpr.x0.dword = getegid(); break; + case AARCH64_SYS_GETTID: /* getttid () */ state_gpr.x0.dword = gettid(); break; + case AARCH64_SYS_BRK: /* brk (unsigned long brk) */ + { + auto heap_memory = g_run_mgr->heap_memory; + if (state_gpr.x0.qword == 0) { + /* init program break (FIXME) */ + state_gpr.x0.qword = heap_memory->heap_cur; + } else if (heap_memory->vma <= state_gpr.x0.qword && + state_gpr.x0.qword < heap_memory->vma + heap_memory->len) { + /* change program break */ + heap_memory->heap_cur = state_gpr.x0.qword; + } else { + elfconv_runtime_error("Unsupported brk(0x%016llx).\n", state_gpr.x0.qword); + } + } break; + case AARCH64_SYS_MUNMAP: /* munmap (unsigned long addr, size_t len) */ + /* TODO */ + state_gpr.x0.qword = 0; + EMPTY_SYSCALL(AARCH64_SYS_MUNMAP); + break; + case AARCH64_SYS_MMAP: /* mmap (void *start, size_t lengt, int prot, int flags, int fd, off_t offset) */ + /* FIXME */ + { + auto heap_memory = g_run_mgr->heap_memory; + if (state_gpr.x4.dword != -1) + elfconv_runtime_error("Unsupported mmap (X4=0x%08x)\n", state_gpr.x4.dword); + if (state_gpr.x5.dword != 0) + elfconv_runtime_error("Unsupported mmap (X5=0x%016llx)\n", state_gpr.x5.qword); + if (state_gpr.x0.qword == 0) { + state_gpr.x0.qword = heap_memory->heap_cur; + heap_memory->heap_cur += state_gpr.x1.qword; + } else { + elfconv_runtime_error("Unsupported mmap (X0=0x%016llx)\n", state_gpr.x0.qword); + } + } + NOP_SYSCALL(AARCH64_SYS_MMAP); + break; + case AARCH64_SYS_MPROTECT: /* mprotect (unsigned long start, size_t len, unsigned long prot) */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_MPROTECT); + break; + case AARCH64_SYS_PRLIMIT64: /* prlimit64 (pid_t pid, unsigned int resource, const struct rlimit64 *new_rlim, struct rlimit64 *oldrlim) */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_PRLIMIT64); + break; + case AARCH64_SYS_GETRANDOM: /* getrandom (char *buf, size_t count, unsigned int flags) */ + { + auto res = getentropy(_ecv_translate_ptr(state_gpr.x0.qword), + static_cast(state_gpr.x1.qword)); + state_gpr.x0.qword = 0 == res ? state_gpr.x1.qword : -1; + } break; + case AARCH64_SYS_STATX: /* statx (int dfd, const char *path, unsigned flags, unsigned mask, struct statx *buffer) */ + { + int dfd = state_gpr.x0.dword; + _ecv_reg_t flags = state_gpr.x2.dword; + if ((flags & _ECV_AT_EMPTY_PATH) == 0) + elfconv_runtime_error("[ERROR] Unsupported statx(flags=0x%08u)\n", flags); + struct stat _stat; + // execute fstat + errno = fstat(dfd, &_stat); + if (errno == 0) { + struct _ecv_statx _statx; + memset(&_statx, 0, sizeof(_statx)); + _statx.stx_mask = _statx.stx_mask = _ECV_STATX_BASIC_STATS; + _statx.stx_blksize = _stat.st_blksize; + _statx.stx_attributes = 0; + _statx.stx_nlink = _stat.st_nlink; + _statx.stx_uid = _stat.st_uid; + _statx.stx_gid = _stat.st_gid; + _statx.stx_mode = _stat.st_mode; + _statx.stx_ino = _stat.st_ino; + _statx.stx_size = _stat.st_size; + _statx.stx_blocks = _stat.st_blocks; + memcpy(_ecv_translate_ptr(state_gpr.x4.qword), &_statx, sizeof(_statx)); + state_gpr.x0.qword = 0; + } else { + state_gpr.x0.qword = -1; + } + } break; + case AARCH64_SYS_RSEQ: + /* TODO */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_RSEQ); + break; + default: + elfconv_runtime_error("Unknown syscall number: %llu, PC: 0x%llx\n", state_gpr.x8.qword, + state_gpr.pc.qword); + break; + } +} \ No newline at end of file diff --git a/runtime/syscalls/SyscallWasi.cpp b/runtime/syscalls/SyscallWasi.cpp new file mode 100644 index 0000000..30f4a6b --- /dev/null +++ b/runtime/syscalls/SyscallWasi.cpp @@ -0,0 +1,308 @@ +#include "SysTable.h" +#include "runtime/Memory.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(ELFC_RUNTIME_SYSCALL_DEBUG) +# define EMPTY_SYSCALL(sysnum) printf("[WARNING] syscall \"" #sysnum "\" is empty now.\n"); +# define NOP_SYSCALL(sysnum) \ + printf("[INFO] syscall \"" #sysnum "\" is nop (but maybe allowd) now.\n"); +#else +# define EMPTY_SYSCALL(sysnum) ; +# define NOP_SYSCALL(sysnum) ; +#endif + +/* + for ioctl syscall +*/ +#define _ECV_TCGETS 0x5401 +#define _ECV_NCCS 19 +typedef uint32_t _ecv_tcflag_t; +typedef uint8_t _ecv_cc_t; +struct _ecv_termios { + _ecv_tcflag_t c_iflag; + _ecv_tcflag_t c_oflag; + _ecv_tcflag_t c_cflag; + _ecv_tcflag_t c_lflag; + _ecv_cc_t c_line; + _ecv_cc_t c_cc[_ECV_NCCS]; +}; + +/* + for statx +*/ +struct _ecv_statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; +}; +struct _ecv_statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct _ecv_statx_timestamp stx_atime; + struct _ecv_statx_timestamp stx_btime; + struct _ecv_statx_timestamp stx_ctime; + struct _ecv_statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t stx_mnt_id; + uint32_t stx_dio_mem_align; + uint32_t stx_dio_offset_align; + uint64_t __spare3[12]; +}; + +#define _ECV_AT_EMPTY_PATH 0x1000 +#define _ECV_STATX_BASIC_STATS 0x000007ffU + +/* + syscall emulate function + + Calling Conventions + arch: arm64, syscall NR: x8, return: x0, arg0: x0, arg1: x1, arg2: x2, arg3: x3, arg4: x4, arg5: x5 + ref: https://blog.xhyeax.com/2022/04/28/arm64-syscall-table/ +*/ +void __svc_wasi_call(void) { + + auto &state_gpr = g_state.gpr; + errno = 0; +#if defined(ELFC_RUNTIME_SYSCALL_DEBUG) + printf("[INFO] __svc_call started. syscall number: %u, PC: 0x%016llx\n", g_state.gpr.x8.dword, + g_state.gpr.pc.qword); +#endif + switch (state_gpr.x8.qword) { + case AARCH64_SYS_IOCTL: /* ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) */ + EMPTY_SYSCALL(AARCH64_SYS_IOCTL) + state_gpr.x0.qword = -1; + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_FACCESSAT: /* faccessat (int dfd, const char *filename, int mode) */ + /* TODO */ + state_gpr.x0.qword = -1; + EMPTY_SYSCALL(AARCH64_SYS_FACCESSAT); + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_OPENAT: /* openat (int dfd, const char* filename, int flags, umode_t mode) */ + if (-100 == state_gpr.x0.dword) + state_gpr.x0.qword = AT_FDCWD; // AT_FDCWD on WASI: -2 (-100 on Linux) + state_gpr.x2.dword = O_RDWR; + state_gpr.x0.dword = openat( + state_gpr.x0.dword, (char *) _ecv_translate_ptr(state_gpr.x1.qword), state_gpr.x2.dword); + if (-1 == state_gpr.x0.dword) + perror("openat error!"); + break; + case AARCH64_SYS_CLOSE: /* int close (unsigned int fd) */ + state_gpr.x0.dword = close(state_gpr.x0.dword); + break; + case AARCH64_SYS_READ: /* read (unsigned int fd, char *buf, size_t count) */ + state_gpr.x0.qword = read(state_gpr.x0.dword, (char *) _ecv_translate_ptr(state_gpr.x1.qword), + static_cast(state_gpr.x2.qword)); + break; + case AARCH64_SYS_WRITE: /* write (unsigned int fd, const char *buf, size_t count) */ + state_gpr.x0.qword = write(state_gpr.x0.dword, _ecv_translate_ptr(state_gpr.x1.qword), + static_cast(state_gpr.x2.qword)); + break; + case AARCH64_SYS_WRITEV: /* writev (unsgined long fd, const struct iovec *vec, unsigned long vlen) */ + { + unsigned long fd = state_gpr.x0.qword; + unsigned long vlen = state_gpr.x2.qword; + auto tr_vec = reinterpret_cast(_ecv_translate_ptr(state_gpr.x1.qword)); + auto cache_vec = reinterpret_cast(malloc(sizeof(iovec) * vlen)); + // translate every iov_base + for (unsigned long i = 0; i < vlen; i++) { + cache_vec[i].iov_base = _ecv_translate_ptr(reinterpret_cast(tr_vec[i].iov_base)); + cache_vec[i].iov_len = tr_vec[i].iov_len; + } + state_gpr.x0.qword = writev(fd, cache_vec, vlen); + free(cache_vec); + } break; + case AARCH64_SYS_READLINKAT: /* readlinkat (int dfd, const char *path, char *buf, int bufsiz) */ + state_gpr.x0.qword = + readlinkat(state_gpr.x0.dword, (const char *) _ecv_translate_ptr(state_gpr.x1.qword), + (char *) _ecv_translate_ptr(state_gpr.x2.qword), state_gpr.x3.dword); + break; + case AARCH64_SYS_NEWFSTATAT: /* newfstatat (int dfd, const char *filename, struct stat *statbuf, int flag) */ + /* TODO */ + state_gpr.x0.qword = -1; + EMPTY_SYSCALL(AARCH64_SYS_NEWFSTATAT); + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_EXIT: /* exit (int error_code) */ exit(state_gpr.x0.dword); break; + case AARCH64_SYS_EXITGROUP: /* exit_group (int error_code) note. there is no function of 'exit_group', so must use syscall. */ + exit(state_gpr.x0.dword); + break; + case AARCH64_SYS_SET_TID_ADDRESS: /* set_tid_address(int *tidptr) */ + { + pid_t tid = 42; + *reinterpret_cast(_ecv_translate_ptr(state_gpr.x0.qword)) = tid; + state_gpr.x0.qword = tid; + } break; + case AARCH64_SYS_FUTEX: /* futex (u32 *uaddr, int op, u32 val, const struct __kernel_timespec *utime, u32 *uaddr2, u23 val3) */ + /* TODO */ + if ((state_gpr.x1.dword & 0x7F) == 0) { + /* FUTEX_WAIT */ + state_gpr.x0.qword = 0; + } else { + elfconv_runtime_error("Unknown futex op 0x%08u\n", state_gpr.x1.dword); + } + NOP_SYSCALL(AARCH64_SYS_FUTEX); + break; + case AARCH64_SYS_SET_ROBUST_LIST: /* set_robust_list (struct robust_list_head *head, size_t len) */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_SET_ROBUST_LIST); + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_CLOCK_GETTIME: /* clock_gettime (clockid_t which_clock, struct __kernel_timespace *tp) */ + EMPTY_SYSCALL(AARCH64_SYS_CLOCK_GETTIME); + state_gpr.x0.qword = -1; + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_TGKILL: /* tgkill (pid_t tgid, pid_t pid, int sig) */ + EMPTY_SYSCALL(AARCH64_SYS_TGKILL); + state_gpr.x0.qword = -1; + errno = _ECV_EACCESS; + break; + case AARCH64_SYS_RT_SIGPROCMASK: /* rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize) */ + /* TODO */ + state_gpr.x0.qword = 0; + EMPTY_SYSCALL(AARCH64_SYS_RT_SIGPROCMASK); + break; + case AARCH64_SYS_RT_SIGACTION: /* rt_sigaction (int signum, const struct sigaction *act, struct sigaction *oldact) */ + state_gpr.x0.qword = -1; + errno = _ECV_EACCESS; + EMPTY_SYSCALL(AARCH64_SYS_RT_SIGACTION) + break; + case AARCH64_SYS_UNAME: /* uname (struct old_utsname* buf) */ + { + struct __my_utsname { + char sysname[65]; + char nodename[65]; + char relase[65]; + char version[65]; + char machine[65]; + } new_utsname = {"Linux", "xxxxxxx-QEMU-Virtual-Machine", + "6.0.0-00-generic", /* cause error if the kernel version is too old. */ + "#0~elfconv", "aarch64"}; + memcpy(_ecv_translate_ptr(state_gpr.x0.qword), &new_utsname, sizeof(new_utsname)); + state_gpr.x0.dword = 0; + } break; + case AARCH64_SYS_GETPID: /* getpid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_GETPPID: /* getppid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_GETTUID: /* getuid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_GETEUID: /* geteuid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_GETGID: /* getgid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_GETEGID: /* getegid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_GETTID: /* getttid () */ state_gpr.x0.dword = 42; break; + case AARCH64_SYS_BRK: /* brk (unsigned long brk) */ + { + auto heap_memory = g_run_mgr->heap_memory; + if (state_gpr.x0.qword == 0) { + /* init program break (FIXME) */ + state_gpr.x0.qword = heap_memory->heap_cur; + } else if (heap_memory->vma <= state_gpr.x0.qword && + state_gpr.x0.qword < heap_memory->vma + heap_memory->len) { + /* change program break */ + heap_memory->heap_cur = state_gpr.x0.qword; + } else { + elfconv_runtime_error("Unsupported brk(0x%016llx).\n", state_gpr.x0.qword); + } + } break; + case AARCH64_SYS_MUNMAP: /* munmap (unsigned long addr, size_t len) */ + /* TODO */ + state_gpr.x0.qword = 0; + EMPTY_SYSCALL(AARCH64_SYS_MUNMAP); + break; + case AARCH64_SYS_MMAP: /* mmap (void *start, size_t lengt, int prot, int flags, int fd, off_t offset) */ + /* FIXME */ + { + auto heap_memory = g_run_mgr->heap_memory; + if (state_gpr.x4.dword != -1) + elfconv_runtime_error("Unsupported mmap (X4=0x%08x)\n", state_gpr.x4.dword); + if (state_gpr.x5.dword != 0) + elfconv_runtime_error("Unsupported mmap (X5=0x%016llx)\n", state_gpr.x5.qword); + if (state_gpr.x0.qword == 0) { + state_gpr.x0.qword = heap_memory->heap_cur; + heap_memory->heap_cur += state_gpr.x1.qword; + } else { + elfconv_runtime_error("Unsupported mmap (X0=0x%016llx)\n", state_gpr.x0.qword); + } + } + NOP_SYSCALL(AARCH64_SYS_MMAP); + break; + case AARCH64_SYS_MPROTECT: /* mprotect (unsigned long start, size_t len, unsigned long prot) */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_MPROTECT); + break; + case AARCH64_SYS_PRLIMIT64: /* prlimit64 (pid_t pid, unsigned int resource, const struct rlimit64 *new_rlim, struct rlimit64 *oldrlim) */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_PRLIMIT64); + break; + case AARCH64_SYS_GETRANDOM: /* getrandom (char *buf, size_t count, unsigned int flags) */ + { + memset(_ecv_translate_ptr(state_gpr.x0.qword), 1, static_cast(state_gpr.x1.qword)); + state_gpr.x0.qword = state_gpr.x1.qword; + } break; + case AARCH64_SYS_STATX: /* statx (int dfd, const char *path, unsigned flags, unsigned mask, struct statx *buffer) */ + { + int dfd = state_gpr.x0.dword; + _ecv_reg_t flags = state_gpr.x2.dword; + if ((flags & _ECV_AT_EMPTY_PATH) == 0) + elfconv_runtime_error("[ERROR] Unsupported statx(flags=0x%08u)\n", flags); + struct stat _stat; + // execute fstat + errno = _ECV_EACCESS; + EMPTY_SYSCALL(AARCH64_SYS_STATX); + if (errno == 0) { + struct _ecv_statx _statx; + memset(&_statx, 0, sizeof(_statx)); + _statx.stx_mask = _statx.stx_mask = _ECV_STATX_BASIC_STATS; + _statx.stx_blksize = _stat.st_blksize; + _statx.stx_attributes = 0; + _statx.stx_nlink = _stat.st_nlink; + _statx.stx_uid = _stat.st_uid; + _statx.stx_gid = _stat.st_gid; + _statx.stx_mode = _stat.st_mode; + _statx.stx_ino = _stat.st_ino; + _statx.stx_size = _stat.st_size; + _statx.stx_blocks = _stat.st_blocks; + memcpy(_ecv_translate_ptr(state_gpr.x4.qword), &_statx, sizeof(_statx)); + state_gpr.x0.qword = 0; + } else { + state_gpr.x0.qword = -1; + } + } break; + case AARCH64_SYS_RSEQ: + /* TODO */ + state_gpr.x0.qword = 0; + NOP_SYSCALL(AARCH64_SYS_RSEQ); + break; + default: + elfconv_runtime_error("Unknown syscall number: %llu, PC: 0x%llx\n", state_gpr.x8.qword, + state_gpr.pc.qword); + break; + } +} \ No newline at end of file diff --git a/scripts/dev.sh b/scripts/dev.sh index e8ddddf..de7112a 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -22,7 +22,7 @@ setting() { EMCCFLAGS="${OPTFLAGS} -I${ROOT_DIR}/backend/remill/include -I${ROOT_DIR}" WASISDK_CXX=${WASI_SDK_PATH}/bin/clang++ WASISDKFLAGS="${OPTFLAGS} --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -I${ROOT_DIR}/backend/remill/include -I${ROOT_DIR}" - ELFCONV_MACROS="-DELFCONV_BROWSER_ENV=1" + ELFCONV_MACROS= ELFCONV_DEBUG_MACROS= WASMCC=$EMCC WASMCCFLAGS=$EMCCFLAGS @@ -47,7 +47,7 @@ aarch64_test() { # generate execute file (lift_test.aarch64) ${CXX} "${CLANGFLAGS}" $ELFCONV_MACROS "$ELFCONV_DEBUG_MACROS" -o lift_test.aarch64 aarch64_test.ll "${AARCH64_TEST_DIR}"/Test.cpp "${AARCH64_TEST_DIR}"/TestHelper.cpp \ - "${AARCH64_TEST_DIR}"/TestInstructions.cpp "${RUNTIME_DIR}"/Memory.cpp "${RUNTIME_DIR}"/Syscall.cpp "${RUNTIME_DIR}"/VmIntrinsics.cpp "${UTILS_DIR}"/Util.cpp "${UTILS_DIR}"/elfconv.cpp + "${AARCH64_TEST_DIR}"/TestInstructions.cpp "${RUNTIME_DIR}"/Memory.cpp "${RUNTIME_DIR}"/syscalls/SyscallNative.cpp "${RUNTIME_DIR}"/VmIntrinsics.cpp "${UTILS_DIR}"/Util.cpp "${UTILS_DIR}"/elfconv.cpp echo -e "[\033[32mINFO\033[0m] Generate lift_test.aarch64" } @@ -89,20 +89,21 @@ main() { case "${TARGET}" in native) cd ${BUILD_LIFTER_DIR} && \ - ${CXX} ${CLANGFLAGS} -o exe.aarch64 lift.ll ${RUNTIME_DIR}/Entry.cpp ${RUNTIME_DIR}/Memory.cpp ${RUNTIME_DIR}/Syscall.cpp ${RUNTIME_DIR}/VmIntrinsics.cpp ${UTILS_DIR}/Util.cpp ${UTILS_DIR}/elfconv.cpp + ${CXX} ${CLANGFLAGS} -o exe.aarch64 lift.ll ${RUNTIME_DIR}/Entry.cpp ${RUNTIME_DIR}/Memory.cpp ${RUNTIME_DIR}/syscalls/SyscallNative.cpp ${RUNTIME_DIR}/VmIntrinsics.cpp ${UTILS_DIR}/Util.cpp ${UTILS_DIR}/elfconv.cpp echo -e "[\033[32mINFO\033[0m] Generate native binary." return 0 ;; wasm-browser) + ELFCONV_MACROS="-DELFC_BROWSER_ENV=1" cd "${BUILD_LIFTER_DIR}" && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Entry.wasm.o -c ${RUNTIME_DIR}/Entry.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Memory.wasm.o -c ${RUNTIME_DIR}/Memory.cpp && \ - $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Syscall.wasm.o -c ${RUNTIME_DIR}/Syscall.cpp && \ + $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Syscall.wasm.o -c ${RUNTIME_DIR}/syscalls/SyscallBrowser.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o VmIntrinsics.wasm.o -c ${RUNTIME_DIR}/VmIntrinsics.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Util.wasm.o -c ${UTILS_DIR}/Util.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o elfconv.wasm.o -c ${UTILS_DIR}/elfconv.cpp && \ - $WASMCC $WASMCCFLAGS -c lift.ll -o lift.wasm.o - $WASMCC $WASMCCFLAGS -o exe.wasm.html -sWASM -sALLOW_MEMORY_GROWTH lift.wasm.o Entry.wasm.o Memory.wasm.o Syscall.wasm.o \ + $WASMCC -c liftO3.ll -o lift.wasm.o + $WASMCC -o exe.wasm.html -sWASM -sALLOW_MEMORY_GROWTH lift.wasm.o Entry.wasm.o Memory.wasm.o Syscall.wasm.o \ VmIntrinsics.wasm.o Util.wasm.o elfconv.wasm.o echo -e "[\033[32mINFO\033[0m] Generate WASM binary." # delete obj @@ -114,12 +115,12 @@ main() { if [ -n "$WASISDK" ]; then WASMCC=$WASISDK_CXX WASMCCFLAGS=$WASISDKFLAGS - ELFCONV_MACROS="${ELFCONV_MACROS} -DWASI_ENV=1 -fno-exceptions" + ELFCONV_MACROS="${ELFCONV_MACROS} -fno-exceptions" fi cd "${BUILD_LIFTER_DIR}" && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Entry.wasm.o -c ${RUNTIME_DIR}/Entry.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Memory.wasm.o -c ${RUNTIME_DIR}/Memory.cpp && \ - $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Syscall.wasm.o -c ${RUNTIME_DIR}/Syscall.cpp && \ + $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Syscall.wasm.o -c ${RUNTIME_DIR}/syscalls/SyscallWasi.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o VmIntrinsics.wasm.o -c ${RUNTIME_DIR}/VmIntrinsics.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o Util.wasm.o -c ${UTILS_DIR}/Util.cpp && \ $WASMCC $WASMCCFLAGS $ELFCONV_MACROS $ELFCONV_DEBUG_MACROS -o elfconv.wasm.o -c ${UTILS_DIR}/elfconv.cpp && \ diff --git a/tests/elfconv/Test.cpp b/tests/elfconv/Test.cpp index e775e0e..4a6ade6 100644 --- a/tests/elfconv/Test.cpp +++ b/tests/elfconv/Test.cpp @@ -10,19 +10,20 @@ using ::testing::TestInfo; using ::testing::UnitTest; #define ECV_PATH(path) "../../../" #path -#define WASMCC_OPTION_HOST_CMD(ident) \ +#define WASMCC_RUNTIME_CMD(ident) \ "${WASI_SDK_PATH}/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -DELFC_WASI_ENV=1 -fno-exceptions -I../../../backend/remill/include -I../../../ -o " #ident \ ".test.wasm.o " \ "-c ../../../runtime/" #ident ".cpp" -#define WASMCC_OPTION_UTILS_CMD(ident) \ +#define WASMCC_RUNTIME_SYSCALL_CMD(ident) \ + "${WASI_SDK_PATH}/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -DELFC_WASI_ENV=1 -fno-exceptions -I../../../backend/remill/include -I../../../ -o " #ident \ + ".test.wasm.o " \ + "-c ../../../runtime/syscalls/" #ident ".cpp" +#define WASMCC_UTILS_CMD(ident) \ "${WASI_SDK_PATH}/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -DELFC_WASI_ENV=1 -fno-exceptions -I../../../backend/remill/include -I../../../ -o " #ident \ ".test.wasm.o " \ "-c ../../../utils/" #ident ".cpp" -#define WASMCC_OPTION_WASM_O(bc_ident) \ - "${WASI_SDK_PATH}/bin/clang++ --sysroot=${WASI_SDK_PATH}/share/wasi-sysroot -c " bc_ident ".bc" \ - " -o " bc_ident ".wasm.o" #define RUNTIME_OBJS \ - "Entry.test.wasm.o Memory.test.wasm.o Syscall.test.wasm.o VmIntrinsics.test.wasm.o Util.test.wasm.o elfconv.test.wasm.o" + "Entry.test.wasm.o Memory.test.wasm.o SyscallWasi.test.wasm.o VmIntrinsics.test.wasm.o Util.test.wasm.o elfconv.test.wasm.o" enum WASI_RUNTIME : uint8_t { WASMTIME, WASMEDGE }; @@ -42,9 +43,12 @@ class TestEnvironment : public ::testing::Environment { // compile `elfconv/runtime` void compile_runtime_emscripten() { - std::string cmds[] = {WASMCC_OPTION_HOST_CMD(Entry), WASMCC_OPTION_HOST_CMD(Memory), - WASMCC_OPTION_HOST_CMD(Syscall), WASMCC_OPTION_HOST_CMD(VmIntrinsics), - WASMCC_OPTION_UTILS_CMD(Util), WASMCC_OPTION_UTILS_CMD(elfconv)}; + std::string cmds[] = {WASMCC_RUNTIME_CMD(Entry), + WASMCC_RUNTIME_CMD(Memory), + WASMCC_RUNTIME_SYSCALL_CMD(SyscallWasi), + WASMCC_RUNTIME_CMD(VmIntrinsics), + WASMCC_UTILS_CMD(Util), + WASMCC_UTILS_CMD(elfconv)}; for (auto &cmd : cmds) { FILE *pipe = popen(cmd.c_str(), "r"); if (!pipe)