#include "spl_syscall.h" #include "include/core_map.h" #include "include/core_vec.h" #include "spl_mcode.h" #include "spl_vm.h" #include #include #include #include /* VM 偏移 -> 宿主地址;size=0 表示不做边界检查。 */ #define VM_X(_vm, off) ((void *)spl_vm_xlate((_vm), (spl_vm_val_t)(off), 0)) #define VM_XN(_vm, off, n) ((void *)spl_vm_xlate((_vm), (spl_vm_val_t)(off), (usize)(n))) #define VM_ASP(_vm) spl_vm_asp(_vm) #define CHECK_NARGS(fname, expected) \ do { \ if (nargs != (expected)) { \ fprintf(stderr, fname ": expected " #expected " args, got %d\n", nargs); \ return -1; \ } \ } while (0) #define SYSCALL_0(name, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 0); \ (void)args; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_1(name, t1, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 1); \ t1 a1 = (t1)(uintptr_t)args[0]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_2(name, t1, t2, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 2); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_3(name, t1, t2, t3, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 3); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ t3 a3 = (t3)(uintptr_t)args[2]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define SYSCALL_4(name, t1, t2, t3, t4, ret_expr) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 4); \ t1 a1 = (t1)(uintptr_t)args[0]; \ t2 a2 = (t2)(uintptr_t)args[1]; \ t3 a3 = (t3)(uintptr_t)args[2]; \ t4 a4 = (t4)(uintptr_t)args[3]; \ return (spl_vm_val_t)(uintptr_t)(ret_expr); \ } #define ADDRCHECK(vm, ptr, size, ctx) \ do { \ uintptr_t _acp = (uintptr_t)(ptr); \ usize _acs = (usize)(size); \ if (!spl_vm_addr_valid(_acp, _acs)) { \ fprintf(stderr, "%s: invalid address %p size=%zu (ip=%zu fp=%zu sp=%zu)\n", (ctx), \ (void *)_acp, _acs, (vm)->ip, (vm)->fp, (vm)->sp); \ spl_vm_backtrace((vm), (vm)->fp); \ (vm)->exit_code = 2; \ return 0; \ } \ } while (0) #define SYSCALL_DUMP(vm) \ do { \ fprintf(stderr, " --- syscall dump (sp=%zu fp=%zu cp=%zu ip=%zu) ---\n", (vm)->sp, \ (vm)->fp, (vm)->cp, (vm)->ip); \ spl_vm_backtrace((vm), (vm)->fp); \ spl_vm_stackdump((vm), (vm)->sp); \ } while (0) #define SYSCALL_FAIL(vm, ...) \ do { \ fprintf(stderr, "syscall error: "); \ fprintf(stderr, __VA_ARGS__); \ fprintf(stderr, "\n"); \ SYSCALL_DUMP(vm); \ (vm)->exit_code = 1; \ return 0; \ } while (0) /* ================================================================= * 从共享核心 spl_rt_core.h 派生的 syscall 包装 * ================================================================= */ #include "spl_rt_core.h" #define SPL_WRAP1(name, fn, t1) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 1); \ return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0]); \ } #define SPL_WRAP1_V(name, fn, t1) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 1); \ fn((t1)(uintptr_t)args[0]); \ return 0; \ } #define SPL_WRAP2(name, fn, t1, t2) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 2); \ return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0], (t2)(uintptr_t)args[1]); \ } #define SPL_WRAP3(name, fn, t1, t2, t3) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 3); \ return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0], (t2)(uintptr_t)args[1], \ (t3)(uintptr_t)args[2]); \ } #define SPL_WRAP4(name, fn, t1, t2, t3, t4) \ static spl_vm_val_t name(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { \ (void)_vm; \ CHECK_NARGS(#name, 4); \ return (spl_vm_val_t)(uintptr_t)fn((t1)(uintptr_t)args[0], (t2)(uintptr_t)args[1], \ (t3)(uintptr_t)args[2], (t4)(uintptr_t)args[3]); \ } /* ================================================================= * OS syscalls * ================================================================= */ SYSCALL_1(vm_exit, int, (exit(a1), (spl_vm_val_t)0)) SYSCALL_1(vm_putchar, int, putchar(a1)) SYSCALL_0(vm_getchar, getchar()) SYSCALL_1(vm_putint, int, (fprintf(stdout, "%d", a1), (spl_vm_val_t)0)) /* FILE* 存于 VM 空间,返回其偏移(不透明句柄)。 */ static spl_vm_val_t vm_file_handle(spl_vm_t *vm, FILE *f) { spl_vm_val_t off; FILE **slot; if (!f) return 0; off = (spl_vm_val_t)(uintptr_t)spl_alloc_ex(VM_ASP(vm), sizeof(FILE *)); if (off == 0) return 0; slot = (FILE **)VM_XN(vm, off, sizeof(FILE *)); if (!slot) return 0; *slot = f; return off; } static FILE *vm_file_get(spl_vm_t *vm, spl_vm_val_t off) { FILE **slot = (FILE **)VM_XN(vm, off, sizeof(FILE *)); return slot ? *slot : NULL; } static spl_vm_val_t vm_putstr(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { const char *s; CHECK_NARGS("vm_putstr", 1); s = (const char *)VM_X(_vm, args[0]); if (s) fputs(s, stdout); return 0; } static spl_vm_val_t vm_fopen(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { const char *path, *mode; CHECK_NARGS("vm_fopen", 2); path = (const char *)VM_X(_vm, args[0]); mode = (const char *)VM_X(_vm, args[1]); return vm_file_handle(_vm, fopen(path, mode)); } static spl_vm_val_t vm_fclose(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { FILE *f; CHECK_NARGS("vm_fclose", 1); f = vm_file_get(_vm, args[0]); return f ? (spl_vm_val_t)fclose(f) : 0; } static spl_vm_val_t vm_fread(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { void *buf; FILE *f; CHECK_NARGS("vm_fread", 4); buf = VM_X(_vm, args[0]); f = vm_file_get(_vm, args[3]); if (!buf || !f) return 0; return (spl_vm_val_t)fread(buf, (size_t)args[1], (size_t)args[2], f); } static spl_vm_val_t vm_fwrite(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { const void *buf; FILE *f; CHECK_NARGS("vm_fwrite", 4); buf = VM_X(_vm, args[0]); f = vm_file_get(_vm, args[3]); if (!buf || !f) return 0; return (spl_vm_val_t)fwrite(buf, (size_t)args[1], (size_t)args[2], f); } static spl_vm_val_t vm_fsize(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { FILE *f; long cur, sz; CHECK_NARGS("vm_fsize", 1); f = vm_file_get(_vm, args[0]); if (!f) return 0; cur = ftell(f); fseek(f, 0, SEEK_END); sz = ftell(f); fseek(f, cur, SEEK_SET); return (spl_vm_val_t)(uintptr_t)(sz < 0 ? 0 : sz); } static spl_vm_val_t vm_std_handle(spl_vm_t *_vm, int which) { if (_vm->stdio_off[which] == 0) { FILE *f = which == 0 ? stdin : (which == 1 ? stdout : stderr); _vm->stdio_off[which] = vm_file_handle(_vm, f); } return _vm->stdio_off[which]; } static spl_vm_val_t vm_stdin(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)args; CHECK_NARGS("vm_stdin", 0); return vm_std_handle(_vm, 0); } static spl_vm_val_t vm_stdout(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)args; CHECK_NARGS("vm_stdout", 0); return vm_std_handle(_vm, 1); } static spl_vm_val_t vm_stderr(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)args; CHECK_NARGS("vm_stderr", 0); return vm_std_handle(_vm, 2); } static spl_vm_val_t vm_read_file(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_read_file", 1); const char *path = (const char *)VM_X(_vm, args[0]); FILE *f; long sz; spl_vm_val_t off; char *buf; if (path == nullptr) { fprintf(stderr, "filepath can't be null"); return 0; } f = fopen(path, "rb"); if (!f) { fprintf(stderr, "filepath %s can't be open", path); return 1; } fseek(f, 0, SEEK_END); sz = ftell(f); fseek(f, 0, SEEK_SET); off = (spl_vm_val_t)(uintptr_t)spl_alloc_ex(VM_ASP(_vm), (uintptr_t)sz + 1); if (off == 0) { fclose(f); return 0; } buf = (char *)VM_XN(_vm, off, (uintptr_t)sz + 1); if (!buf) { fclose(f); return 0; } { size_t nread = fread(buf, 1, (size_t)sz, f); buf[nread] = '\0'; } fclose(f); return off; } /* ================================================================= * mem syscalls —— 使用 spl_rt_core.h 中的实现 * ================================================================= */ static spl_vm_val_t spl_sys_vm_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { uintptr_t sz; spl_vm_val_t p; CHECK_NARGS("vm_alloc", 1); sz = (uintptr_t)args[0]; if (sz == 0) SYSCALL_FAIL(_vm, "vm_alloc: zero size"); if (sz > ((uintptr_t)1 << 32)) SYSCALL_FAIL(_vm, "vm_alloc: size too large (%zu)", (size_t)sz); p = (spl_vm_val_t)(uintptr_t)spl_alloc_ex(VM_ASP(_vm), sz); if (p == 0) SYSCALL_FAIL(_vm, "vm_alloc: alloc(%zu) failed", (size_t)sz); return p; } static spl_vm_val_t spl_sys_vm_free(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_free", 1); spl_free_ex(VM_ASP(_vm), (void *)(uintptr_t)args[0]); return 0; } static spl_vm_val_t spl_sys_vm_realloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { uintptr_t sz; spl_vm_val_t np; CHECK_NARGS("vm_realloc", 2); sz = (uintptr_t)args[1]; if (args[0] == 0) SYSCALL_FAIL(_vm, "vm_realloc: NULL ptr"); if (sz == 0) SYSCALL_FAIL(_vm, "vm_realloc: zero size"); np = (spl_vm_val_t)(uintptr_t)spl_realloc_ex(VM_ASP(_vm), (void *)(uintptr_t)args[0], sz); if (np == 0) SYSCALL_FAIL(_vm, "vm_realloc: realloc failed"); return np; } static spl_vm_val_t spl_sys_vm_memcpy(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { void *dst, *src; uintptr_t n; CHECK_NARGS("vm_memcpy", 3); n = (uintptr_t)args[2]; if (n == 0) return args[0]; dst = VM_X(_vm, args[0]); src = VM_X(_vm, args[1]); if (!dst || !src) SYSCALL_FAIL(_vm, "vm_memcpy: invalid address"); vm_memcpy(dst, src, n); return args[0]; } static spl_vm_val_t spl_sys_vm_memmove(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { void *dst, *src; uintptr_t n; CHECK_NARGS("vm_memmove", 3); n = (uintptr_t)args[2]; if (n == 0) return args[0]; dst = VM_X(_vm, args[0]); src = VM_X(_vm, args[1]); if (!dst || !src) SYSCALL_FAIL(_vm, "vm_memmove: invalid address"); vm_memmove(dst, src, n); return args[0]; } static spl_vm_val_t spl_sys_vm_memcmp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { const void *a, *b; uintptr_t n; CHECK_NARGS("vm_memcmp", 3); a = VM_X(_vm, args[0]); b = VM_X(_vm, args[1]); n = (uintptr_t)args[2]; if (n && (!a || !b)) SYSCALL_FAIL(_vm, "vm_memcmp: invalid address"); return (spl_vm_val_t)(uintptr_t)vm_memcmp(a, b, n); } /* ================================================================= * Vec syscalls(参数按 VM 偏移解释) * ================================================================= */ #define VM_VEC_BYTES ((uintptr_t)sizeof(spl_vec_t)) #define VM_MAP_BYTES ((uintptr_t)sizeof(spl_map_t)) static spl_vm_val_t spl_sys_vm_vec_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_valid", 1); return (spl_vm_val_t)(uintptr_t)spl_vec_valid_ex(VM_XN(_vm, args[0], VM_VEC_BYTES)); } static spl_vm_val_t spl_sys_vm_vec_push_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_push_raw", 2); return (spl_vm_val_t)(uintptr_t)spl_vec_push_raw_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1])); } static spl_vm_val_t spl_sys_vm_vec_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_push", 2); return (spl_vm_val_t)(uintptr_t)spl_vec_push_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1])); } static spl_vm_val_t spl_sys_vm_vec_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_get", 3); return (spl_vm_val_t)(uintptr_t)spl_vec_get_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1], (void **)VM_XN(_vm, args[2], sizeof(void *))); } static spl_vm_val_t spl_sys_vm_vec_allocate(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_allocate", 4); return (spl_vm_val_t)(uintptr_t)spl_vec_allocate_out_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1], (uintptr_t)args[2], (uintptr_t)args[3]); } static spl_vm_val_t spl_sys_vm_vec_reserve_raw(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_reserve_raw", 2); return (spl_vm_val_t)(uintptr_t)spl_vec_reserve_raw_void_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1]); } static spl_vm_val_t spl_sys_vm_vec_append(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_append", 3); return (spl_vm_val_t)(uintptr_t)spl_vec_append_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1]), (uintptr_t)args[2]); } static spl_vm_val_t spl_sys_vm_vec_set(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_set", 3); return (spl_vm_val_t)(uintptr_t)spl_vec_set_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), (uintptr_t)args[1], VM_X(_vm, args[2])); } static spl_vm_val_t spl_sys_vm_vec_pop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_pop", 2); return (spl_vm_val_t)(uintptr_t)spl_vec_pop_ex(VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_X(_vm, args[1])); } static spl_vm_val_t spl_sys_vm_vec_clone(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_clone", 2); return (spl_vm_val_t)(uintptr_t)spl_vec_clone_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES), VM_XN(_vm, args[1], VM_VEC_BYTES)); } static spl_vm_val_t spl_sys_vm_vec_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_vec_drop", 1); return (spl_vm_val_t)(uintptr_t)spl_vec_drop_ex(VM_ASP(_vm), VM_XN(_vm, args[0], VM_VEC_BYTES)); } static spl_vm_val_t spl_sys_vm_bytes_eq(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_bytes_eq", 4); return (spl_vm_val_t)(uintptr_t)spl_bytes_eq_ex(VM_ASP(_vm), VM_X(_vm, args[0]), (uintptr_t)args[1], VM_X(_vm, args[2]), (uintptr_t)args[3]); } /* ================================================================= * Map syscalls * ================================================================= */ static spl_vm_val_t spl_sys_vm_map_valid(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_valid", 1); return (spl_vm_val_t)(uintptr_t)spl_map_valid_ex(VM_XN(_vm, args[0], VM_MAP_BYTES)); } static spl_vm_val_t spl_sys_vm_map_reserve(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_reserve", 2); return (spl_vm_val_t)(uintptr_t)spl_map_reserve_void_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), (uintptr_t)args[1]); } static spl_vm_val_t spl_sys_vm_map_put(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_put", 3); return (spl_vm_val_t)(uintptr_t)spl_map_put_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), VM_X(_vm, args[1]), VM_X(_vm, args[2])); } static spl_vm_val_t spl_sys_vm_map_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_get", 3); return (spl_vm_val_t)(uintptr_t)spl_map_get_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), VM_X(_vm, args[1]), VM_X(_vm, args[2])); } static spl_vm_val_t spl_sys_vm_map_del(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_del", 2); return (spl_vm_val_t)(uintptr_t)spl_map_del_ex( VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES), VM_X(_vm, args[1])); } static spl_vm_val_t spl_sys_vm_map_clear(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_clear", 1); return (spl_vm_val_t)(uintptr_t)spl_map_clear_ex(VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES)); } static spl_vm_val_t spl_sys_vm_map_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_map_drop", 1); return (spl_vm_val_t)(uintptr_t)spl_map_drop_ex(VM_ASP(_vm), VM_XN(_vm, args[0], VM_MAP_BYTES)); } /* ================================================================= * printf / timestamp * ================================================================= */ static spl_vm_val_t vm_printf(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { if (nargs <= 0) return 0; const spl_vm_val_t *fmt_slice = (const spl_vm_val_t *)VM_XN(_vm, args[0], 2 * sizeof(spl_vm_val_t)); const char *fmt; usize fmt_len; if (!fmt_slice) return 0; fmt = (const char *)VM_X(_vm, fmt_slice[0]); fmt_len = (usize)fmt_slice[1]; if (!fmt && fmt_len) return 0; if (nargs <= 1) { fwrite(fmt, 1, fmt_len, stdout); return (spl_vm_val_t)nargs; } typedef VEC(char) string_builder_t; string_builder_t buffer; vec_init(buffer); int arg_idx = 1; char tmp_buf[32]; for (usize i = 0; i < fmt_len; ++i) { if (fmt[i] != '%') { vec_push(buffer, fmt[i]); continue; } if (++i >= fmt_len) break; if (arg_idx >= nargs) break; switch (fmt[i]) { case 'd': { memset(tmp_buf, 0, sizeof(tmp_buf)); snprintf(tmp_buf, sizeof(tmp_buf), "%zd", (isize)args[arg_idx]); for (usize j = 0; tmp_buf[j] != '\0'; ++j) vec_push(buffer, tmp_buf[j]); arg_idx++; break; } case 'c': vec_push(buffer, (char)args[arg_idx]); arg_idx++; break; case 's': { const spl_vm_val_t *s = (const spl_vm_val_t *)VM_XN(_vm, args[arg_idx], 2 * sizeof(spl_vm_val_t)); const char *p = s ? (const char *)VM_X(_vm, s[0]) : NULL; usize l = s ? (usize)s[1] : 0; if (p) for (usize j = 0; j < l; ++j) vec_push(buffer, p[j]); arg_idx++; break; } default: vec_push(buffer, '%'); vec_push(buffer, fmt[i]); break; } } if (vec_size(buffer) > 0) fwrite(buffer.data, 1, vec_size(buffer), stdout); vec_free(buffer); return (spl_vm_val_t)nargs; } static spl_vm_val_t vm_timestamp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_timestamp", 1); spl_vm_val_t arg = args[0]; struct timespec ts; int has_time = (timespec_get(&ts, TIME_UTC) == TIME_UTC); switch (arg) { case 0: return has_time ? 1 : 0; case 1: return has_time ? (spl_vm_val_t)ts.tv_sec : 0; case 2: return has_time ? (spl_vm_val_t)ts.tv_nsec : 0; case 3: if (!_vm) return 0; return (spl_vm_val_t)_vm->steps; case 5: if (!_vm) return 0; return (spl_vm_val_t)_vm->ncalls; case 4: return has_time ? (spl_vm_val_t)((unsigned long long)ts.tv_sec * 1000000000ull + (unsigned long long)ts.tv_nsec) : 0; default: fprintf(stderr, "vm_timestamp: invalid arg %zu\n", (size_t)arg); return 0; } } /* ================================================================= * nested-VM syscalls * ================================================================= */ /* 通用双向桥(配置层策略,非 VM 平台 API): * 在子 VM 上安装「未解析 native 处理器」,把子 VM 的未解析调用按名转发到 * 宿主(调用者)VM 中由 `entry` 指定的函数。宿主函数收到: * (ctx, name_off, name_len, nested_vm, arg_base, nargs) * 平台/C 侧**纯转发**:不复制实参、不限元数、不了解类型;聚合读写由宿主用 * vm_stack_get / vm_mem_read / vm_mem_alloc / vm_mem_write 自行完成。 * `entry` 由宿主显式给出,平台不预设任何函数名。 */ typedef struct { spl_vm_t *host; void *ctx; char entry[128]; } spl_bridge_t; static spl_vm_val_t spl_bridge_forward(spl_vm_t *nested, const spl_vm_call_t *call, void *user) { spl_bridge_t *b = (spl_bridge_t *)user; spl_vm_val_t name_off; spl_vm_val_t args[6]; spl_vm_call_t back; usize n; usize arg_base; if (!b || !b->host || !call || !call->name || b->entry[0] == '\0') return 0; n = strlen(call->name); /* 名拷进宿主 VM 内存,宿主按偏移读取。 */ name_off = spl_vm_mem_alloc(b->host, n + 1); if (!name_off) return 0; if (spl_vm_mem_write(b->host, name_off, call->name, n + 1) != 0) return 0; arg_base = spl_vm_call_arg_base(nested, call); if (arg_base == (usize)-1) return 0; args[0] = (spl_vm_val_t)(uintptr_t)b->ctx; args[1] = name_off; args[2] = (spl_vm_val_t)n; args[3] = (spl_vm_val_t)(uintptr_t)nested; args[4] = (spl_vm_val_t)arg_base; args[5] = (spl_vm_val_t)call->nargs; back.name = b->entry; back.args = args; back.nargs = 6; back.ret = 0; if (spl_vm_invoke(b->host, &back) != 0) return 0; return back.ret; } static spl_vm_val_t vm_new(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_new", 0); (void)args; (void)_vm; spl_vm_t *vm = (spl_vm_t *)malloc(sizeof(spl_vm_t)); if (!vm) return 0; spl_vm_init(vm); return (spl_vm_val_t)(uintptr_t)vm; } /* vm_set_foreign(vm, entry, ctx):宿主显式指定处理器函数名。 */ static spl_vm_val_t sc_vm_set_foreign(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { spl_vm_t *vm; spl_bridge_t *b; const spl_vm_val_t *entry; const char *eptr; usize elen; CHECK_NARGS("vm_set_foreign", 3); vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm || !_vm) return -1; entry = (const spl_vm_val_t *)VM_XN(_vm, args[1], 2 * sizeof(spl_vm_val_t)); if (!entry) return -1; eptr = (const char *)VM_X(_vm, entry[0]); elen = (usize)entry[1]; if (!eptr || elen == 0 || elen >= sizeof(((spl_bridge_t *)0)->entry)) return -1; b = (spl_bridge_t *)malloc(sizeof(*b)); if (!b) return -1; b->host = _vm; b->ctx = (void *)(uintptr_t)args[2]; memcpy(b->entry, eptr, elen); b->entry[elen] = '\0'; spl_vm_set_foreign(vm, spl_bridge_forward, b); return 0; } static spl_vm_val_t vm_drop(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_drop", 1); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm) return 0; if (vm->foreign == spl_bridge_forward && vm->foreign_ctx) free(vm->foreign_ctx); if (vm->prog) { spl_prog_drop(vm->prog); free(vm->prog); vm->prog = NULL; } spl_vm_drop(vm); free(vm); return 0; } static spl_vm_val_t vm_load(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_load", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *path = (const char *)VM_X(_vm, args[1]); if (!vm || !path) return -1; spl_prog_t *prog = (spl_prog_t *)malloc(sizeof(spl_prog_t)); if (!prog) return -1; if (spl_prog_load_from_file(path, prog) != 0) { free(prog); return -1; } spl_syscall_register(prog); if (spl_vm_load_prog(vm, prog) != 0) { spl_prog_drop(prog); free(prog); return -1; } return (spl_vm_val_t)(uintptr_t)prog; } static spl_vm_val_t vm_load_from_buffer(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_load_from_buffer", 3); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *buf = (const char *)VM_XN(_vm, args[1], (usize)args[2]); usize len = (usize)args[2]; spl_prog_t *prog; if (!vm || !buf) return -1; prog = (spl_prog_t *)malloc(sizeof(spl_prog_t)); if (!prog) return -1; if (spl_prog_load_from_buffer(buf, len, prog) != 0) { free(prog); return -1; } /* 不自动注入任何 native/syscall:解析策略由使用者配置。 */ if (spl_vm_load_prog(vm, prog) != 0) { spl_prog_drop(prog); free(prog); return -1; } return 0; } static spl_vm_val_t vm_push(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_push", 2); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; spl_vm_val_t val = args[1]; if (!vm) return -1; if (vm->sp >= vm->config.max_stack_depth) { fprintf(stderr, "vm_push: stack overflow\n"); return -1; } vm->stacks.data[vm->sp++] = val; return 0; } static spl_vm_val_t vm_call(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { CHECK_NARGS("vm_call", 3); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; const char *name = (const char *)VM_X(_vm, args[1]); spl_vm_val_t call_nargs = args[2]; if (!vm || !name) return -1; if (spl_vm_call_entry(vm, name, (int)call_nargs) != 0) { fprintf(stderr, "vm_call: function '%s' not found or bad ABI\n", name); return -1; } return 0; } static spl_vm_val_t vm_run(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_run", 1); spl_vm_t *vm = (spl_vm_t *)(uintptr_t)args[0]; if (!vm) return -1; spl_vm_run_until(vm, 0); return (spl_vm_val_t)vm->ret_val; } /* ---- 栈 / 结果 / 内存 访问(不暴露宿主指针) ---- */ static spl_vm_val_t sc_vm_ret_val(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_ret_val", 1); return spl_vm_ret_val((spl_vm_t *)(uintptr_t)args[0]); } static spl_vm_val_t sc_vm_sp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_sp", 1); return (spl_vm_val_t)spl_vm_sp((spl_vm_t *)(uintptr_t)args[0]); } static spl_vm_val_t sc_vm_fp(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_fp", 1); return (spl_vm_val_t)spl_vm_fp((spl_vm_t *)(uintptr_t)args[0]); } static spl_vm_val_t sc_vm_stack_get(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_stack_get", 2); return spl_vm_stack_get((spl_vm_t *)(uintptr_t)args[0], (usize)args[1]); } static spl_vm_val_t sc_vm_stack_set(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_stack_set", 3); return (spl_vm_val_t)spl_vm_stack_set((spl_vm_t *)(uintptr_t)args[0], (usize)args[1], args[2]); } static spl_vm_val_t sc_vm_mem_alloc(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { (void)_vm; CHECK_NARGS("vm_mem_alloc", 2); return spl_vm_mem_alloc((spl_vm_t *)(uintptr_t)args[0], (usize)args[1]); } static spl_vm_val_t sc_vm_mem_read(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { spl_vm_t *vm; void *dst; usize n; CHECK_NARGS("vm_mem_read", 4); vm = (spl_vm_t *)(uintptr_t)args[0]; n = (usize)args[3]; dst = VM_XN(_vm, args[2], n); if ((!dst) && n) return -1; return (spl_vm_val_t)spl_vm_mem_read(vm, (spl_vm_val_t)args[1], dst, n); } static spl_vm_val_t sc_vm_mem_write(spl_vm_t *_vm, int nargs, spl_vm_val_t *args) { spl_vm_t *vm; void *src; usize n; CHECK_NARGS("vm_mem_write", 4); vm = (spl_vm_t *)(uintptr_t)args[0]; n = (usize)args[3]; src = VM_XN(_vm, args[2], n); if ((!src) && n) return -1; return (spl_vm_val_t)spl_vm_mem_write(vm, (spl_vm_val_t)args[1], src, n); } /* ================================================================= * Registration * ================================================================= */ void spl_syscall_register(spl_prog_t *prog) { static spl_vm_native_t table[] = { {"vm_exit", 0, vm_exit}, {"vm_putchar", 0, vm_putchar}, {"vm_getchar", 0, vm_getchar}, {"vm_putint", 0, vm_putint}, {"vm_putstr", 0, vm_putstr}, {"vm_fopen", 0, vm_fopen}, {"vm_fclose", 0, vm_fclose}, {"vm_fread", 0, vm_fread}, {"vm_fwrite", 0, vm_fwrite}, {"vm_fsize", 0, vm_fsize}, {"vm_stdin", 0, vm_stdin}, {"vm_stdout", 0, vm_stdout}, {"vm_stderr", 0, vm_stderr}, {"vm_read_file", 0, vm_read_file}, {"vm_alloc", 0, spl_sys_vm_alloc}, {"vm_free", 0, spl_sys_vm_free}, {"vm_realloc", 0, spl_sys_vm_realloc}, {"vm_memcpy", 0, spl_sys_vm_memcpy}, {"vm_memmove", 0, spl_sys_vm_memmove}, {"vm_memcmp", 0, spl_sys_vm_memcmp}, {"vm_printf", 0, vm_printf}, {"vm_vec_valid", 0, spl_sys_vm_vec_valid}, {"vm_vec_push_raw", 0, spl_sys_vm_vec_push_raw}, {"vm_vec_push", 0, spl_sys_vm_vec_push}, {"vm_vec_get", 0, spl_sys_vm_vec_get}, {"vm_vec_allocate", 0, spl_sys_vm_vec_allocate}, {"vm_vec_reserve_raw", 0, spl_sys_vm_vec_reserve_raw}, {"vm_vec_append", 0, spl_sys_vm_vec_append}, {"vm_vec_set", 0, spl_sys_vm_vec_set}, {"vm_vec_pop", 0, spl_sys_vm_vec_pop}, {"vm_vec_clone", 0, spl_sys_vm_vec_clone}, {"vm_vec_drop", 0, spl_sys_vm_vec_drop}, {"vm_bytes_eq", 0, spl_sys_vm_bytes_eq}, {"vm_map_valid", 0, spl_sys_vm_map_valid}, {"vm_map_reserve", 0, spl_sys_vm_map_reserve}, {"vm_map_put", 0, spl_sys_vm_map_put}, {"vm_map_get", 0, spl_sys_vm_map_get}, {"vm_map_del", 0, spl_sys_vm_map_del}, {"vm_map_clear", 0, spl_sys_vm_map_clear}, {"vm_map_drop", 0, spl_sys_vm_map_drop}, {"vm_timestamp", 0, vm_timestamp}, {"vm_new", 0, vm_new}, {"vm_set_foreign", 0, sc_vm_set_foreign}, {"vm_drop", 0, vm_drop}, {"vm_load", 0, vm_load}, {"vm_load_from_buffer", 0, vm_load_from_buffer}, {"vm_push", 0, vm_push}, {"vm_call", 0, vm_call}, {"vm_run", 0, vm_run}, {"vm_ret_val", 0, sc_vm_ret_val}, {"vm_sp", 0, sc_vm_sp}, {"vm_fp", 0, sc_vm_fp}, {"vm_stack_get", 0, sc_vm_stack_get}, {"vm_stack_set", 0, sc_vm_stack_set}, {"vm_mem_alloc", 0, sc_vm_mem_alloc}, {"vm_mem_read", 0, sc_vm_mem_read}, {"vm_mem_write", 0, sc_vm_mem_write}, }; int n = (int)(sizeof(table) / sizeof(table[0])); if (!prog) return; vec_for(prog->natives, i) { spl_vm_native_t *nat = &vec_at(prog->natives, i); if (!nat->name || nat->impl_fn) continue; for (int j = 0; j < n; j++) { if (strcmp(nat->name, table[j].name) == 0) { nat->impl_fn = table[j].impl_fn; break; } } } }