Path: blob/main/system/lib/standalone/standalone.c
6174 views
/*1* Copyright 2019 The Emscripten Authors. All rights reserved.2* Emscripten is available under two separate licenses, the MIT license and the3* University of Illinois/NCSA Open Source License. Both these licenses can be4* found in the LICENSE file.5*/67#define _GNU_SOURCE8#include <assert.h>9#include <errno.h>10#include <signal.h>11#include <stdlib.h>12#include <string.h>13#include <sys/mman.h>14#include <malloc.h>15#include <syscall_arch.h>16#include <time.h>17#include <unistd.h>1819#include <emscripten.h>20#include <emscripten/heap.h>21#include <emscripten/console.h>22#include <wasi/api.h>23#include <wasi/wasi-helpers.h>2425#include "lock.h"26#include "emscripten_internal.h"27#include "unwind.h"2829/*30* WASI support code. These are compiled with the program, and call out31* using wasi APIs, which can be provided either by a wasi VM or by our32* emitted JS.33*/3435// libc3637void _abort_js(void) {38__builtin_trap();39/* Beyond this point should be unreachable. */40_Exit(117);41}4243_Static_assert(CLOCK_REALTIME == __WASI_CLOCKID_REALTIME, "must match");44_Static_assert(CLOCK_MONOTONIC == __WASI_CLOCKID_MONOTONIC, "must match");45_Static_assert(CLOCK_PROCESS_CPUTIME_ID == __WASI_CLOCKID_PROCESS_CPUTIME_ID, "must match");46_Static_assert(CLOCK_THREAD_CPUTIME_ID == __WASI_CLOCKID_THREAD_CPUTIME_ID, "must match");4748// mmap support is nonexistent. TODO: emulate simple mmaps using49// stdio + malloc, which is slow but may help some things?5051// Mark these as weak so that wasmfs does not collide with it. That is, if52// wasmfs is in use, we want to use that and not this.53weak int _mmap_js(size_t length,54int prot,55int flags,56int fd,57off_t offset,58int* allocated,59void** addr) {60return -ENOSYS;61}6263weak int _munmap_js(64intptr_t addr, size_t length, int prot, int flags, int fd, off_t offset) {65return -ENOSYS;66}6768weak int _poll_js(void *fds, int nfds, int timeout, void* ctx, void* arg) {69return -ENOSYS;70}7172// open(), etc. - we just support the standard streams, with no73// corner case error checking; everything else is not permitted.74// TODO: full file support for WASI, or an option for it75// open()76weak int __syscall_openat(int dirfd, intptr_t path, int flags, ...) {77if (!strcmp((const char*)path, "/dev/stdin")) {78return STDIN_FILENO;79}80if (!strcmp((const char*)path, "/dev/stdout")) {81return STDOUT_FILENO;82}83if (!strcmp((const char*)path, "/dev/stderr")) {84return STDERR_FILENO;85}86return -EPERM;87}8889weak int __syscall_ioctl(int fd, int op, ...) {90return -ENOSYS;91}9293weak int __syscall_fcntl64(int fd, int cmd, ...) {94return -ENOSYS;95}9697weak int __syscall_fstat64(int fd, intptr_t buf) {98return -ENOSYS;99}100101weak int __syscall_stat64(intptr_t path, intptr_t buf) {102return -ENOSYS;103}104105weak int __syscall_dup(int fd) {106return -ENOSYS;107}108109weak int __syscall_mkdirat(int dirfd, intptr_t path, int mode) {110return -ENOSYS;111}112113weak int __syscall_newfstatat(int dirfd, intptr_t path, intptr_t buf, int flags) {114return -ENOSYS;115}116117weak int __syscall_lstat64(intptr_t path, intptr_t buf) {118return -ENOSYS;119}120121// Emscripten additions122123size_t emscripten_get_heap_max() {124// In standalone mode we don't have any wasm instructions to access the max125// memory size so the best we can do (without calling an import) is return126// the current heap size.127return emscripten_get_heap_size();128}129130int emscripten_resize_heap(size_t size) {131#if defined(EMSCRIPTEN_MEMORY_GROWTH)132size_t old_size = __builtin_wasm_memory_size(0) * WASM_PAGE_SIZE;133assert(old_size < size);134ssize_t diff = (size - old_size + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE;135size_t result = __builtin_wasm_memory_grow(0, diff);136if (result != (size_t)-1) {137#if !defined(EMSCRIPTEN_PURE_WASI)138// Success, update JS (see https://github.com/WebAssembly/WASI/issues/82)139emscripten_notify_memory_growth(0);140#endif141return 1;142}143#endif144return 0;145}146147// Call clock_gettime with a particular clock and return the result in ms.148static double clock_gettime_ms(clockid_t clock) {149struct timespec ts;150if (clock_gettime(clock, &ts)) {151return 0;152}153return (double)ts.tv_sec * 1000 + (double)ts.tv_nsec / 1000000;154}155156weak double emscripten_get_now(void) {157return clock_gettime_ms(CLOCK_MONOTONIC);158}159160weak double emscripten_date_now(void) {161return clock_gettime_ms(CLOCK_REALTIME);162}163164// C++ ABI165166#if EMSCRIPTEN_NOCATCH167// When exception catching is disabled, we stub out calls to `__cxa_throw`.168// Otherwise, `__cxa_throw` will be imported from the host.169void __cxa_throw(void* ptr, void* type, void* destructor) {170abort();171}172#endif173174// WasmFS integration. We stub out file preloading and such, that are not175// expected to work anyhow.176177size_t _wasmfs_get_num_preloaded_files() { return 0; }178179size_t _wasmfs_get_num_preloaded_dirs() { return 0; }180181int _wasmfs_get_preloaded_file_size(int index) { return 0; }182183int _wasmfs_get_preloaded_file_mode(int index) { return 0; }184185void _wasmfs_copy_preloaded_file_data(int index, void* buffer) {}186187void _wasmfs_get_preloaded_parent_path(int index, void* buffer) {}188189void _wasmfs_get_preloaded_child_path(int index, void* buffer) {}190191void _wasmfs_get_preloaded_path_name(int index, void* buffer) {}192193// Import the VM's fd_write under a different name. Then we can interpose in194// between it and WasmFS's fd_write. That is, libc calls fd_write, which WasmFS195// implements. And WasmFS will forward actual writing to stdout/stderr to the196// VM's fd_write. (This allows WasmFS to do work in the middle, for example, it197// could support embedded files and other functionality.)198__attribute__((import_module("wasi_snapshot_preview1"),199import_name("fd_write"))) __wasi_errno_t200imported__wasi_fd_write(__wasi_fd_t fd,201const __wasi_ciovec_t* iovs,202size_t iovs_len,203__wasi_size_t* nwritten);204205// Write a buffer + a newline.206static void wasi_writeln_n(__wasi_fd_t fd, const char* buffer, size_t len) {207struct __wasi_ciovec_t iovs[2];208iovs[0].buf = (uint8_t*)buffer;209iovs[0].buf_len = len;210iovs[1].buf = (uint8_t*)"\n";211iovs[1].buf_len = 1;212__wasi_size_t nwritten;213imported__wasi_fd_write(fd, iovs, 2, &nwritten);214}215216static void wasi_writeln(__wasi_fd_t fd, const char* buffer) {217return wasi_writeln_n(fd, buffer, strlen(buffer));218}219220weak void emscripten_out(const char* text) { wasi_writeln(1, text); }221222weak void emscripten_err(const char* text) { wasi_writeln(2, text); }223224weak void emscripten_dbg(const char* text) { wasi_writeln(2, text); }225226weak void emscripten_outn(const char* text, size_t len) {227wasi_writeln_n(1, text, len);228}229230weak void emscripten_errn(const char* text, size_t len) {231wasi_writeln_n(2, text, len);232}233234weak void emscripten_dbgn(const char* text, size_t len) {235wasi_writeln_n(2, text, len);236}237238__attribute__((import_module("wasi_snapshot_preview1"),239import_name("fd_read"))) __wasi_errno_t240imported__wasi_fd_read(__wasi_fd_t fd,241const __wasi_ciovec_t* iovs,242size_t iovs_len,243__wasi_size_t* nread);244245int _wasmfs_stdin_get_char(void) {246char c;247struct __wasi_ciovec_t iov;248iov.buf = (uint8_t*)&c;249iov.buf_len = 1;250__wasi_size_t nread;251imported__wasi_fd_read(0, &iov, 1, &nread);252if (nread == 0) {253return -1;254}255return c;256}257258// In the non-standalone build we define this helper function in JS to avoid259// signature mismatch issues.260// See: https://github.com/emscripten-core/posixtestsuite/issues/6261void __call_sighandler(sighandler_t handler, int sig) {262handler(sig);263}264265int _setitimer_js(int which, double timeout) {266// There is no API to let us set timers in standalone mode atm. Return an267// error.268errno = ENOTSUP;269return -1;270}271272weak uintptr_t emscripten_stack_snapshot(void) {273return 0;274}275276weak uint32_t emscripten_stack_unwind_buffer(uintptr_t pc,277uintptr_t* buffer,278uint32_t depth) {279return 0;280}281282weak const char* emscripten_pc_get_function(uintptr_t pc) {283return NULL;284}285286weak const char* emscripten_pc_get_file(uintptr_t pc) {287return NULL;288}289290weak int emscripten_pc_get_line(uintptr_t pc) {291return 0;292}293294weak int emscripten_pc_get_column(uintptr_t pc) {295return 0;296}297298weak void* emscripten_return_address(int level) {299return NULL;300}301302weak int _emscripten_sanitizer_use_colors(void) {303return 1;304}305306weak char* _emscripten_sanitizer_get_option(const char* name) {307return strdup("");308}309310weak void _emscripten_get_progname(char* buf, int length) {311strncpy(buf, "<unknown>", length);312}313314weak void _emscripten_runtime_keepalive_clear() {}315316void __throw_exception_with_stack_trace(_Unwind_Exception* exception_object) {317_Unwind_RaiseException(exception_object);318}319320321