Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/standalone/standalone.c
6174 views
1
/*
2
* Copyright 2019 The Emscripten Authors. All rights reserved.
3
* Emscripten is available under two separate licenses, the MIT license and the
4
* University of Illinois/NCSA Open Source License. Both these licenses can be
5
* found in the LICENSE file.
6
*/
7
8
#define _GNU_SOURCE
9
#include <assert.h>
10
#include <errno.h>
11
#include <signal.h>
12
#include <stdlib.h>
13
#include <string.h>
14
#include <sys/mman.h>
15
#include <malloc.h>
16
#include <syscall_arch.h>
17
#include <time.h>
18
#include <unistd.h>
19
20
#include <emscripten.h>
21
#include <emscripten/heap.h>
22
#include <emscripten/console.h>
23
#include <wasi/api.h>
24
#include <wasi/wasi-helpers.h>
25
26
#include "lock.h"
27
#include "emscripten_internal.h"
28
#include "unwind.h"
29
30
/*
31
* WASI support code. These are compiled with the program, and call out
32
* using wasi APIs, which can be provided either by a wasi VM or by our
33
* emitted JS.
34
*/
35
36
// libc
37
38
void _abort_js(void) {
39
__builtin_trap();
40
/* Beyond this point should be unreachable. */
41
_Exit(117);
42
}
43
44
_Static_assert(CLOCK_REALTIME == __WASI_CLOCKID_REALTIME, "must match");
45
_Static_assert(CLOCK_MONOTONIC == __WASI_CLOCKID_MONOTONIC, "must match");
46
_Static_assert(CLOCK_PROCESS_CPUTIME_ID == __WASI_CLOCKID_PROCESS_CPUTIME_ID, "must match");
47
_Static_assert(CLOCK_THREAD_CPUTIME_ID == __WASI_CLOCKID_THREAD_CPUTIME_ID, "must match");
48
49
// mmap support is nonexistent. TODO: emulate simple mmaps using
50
// stdio + malloc, which is slow but may help some things?
51
52
// Mark these as weak so that wasmfs does not collide with it. That is, if
53
// wasmfs is in use, we want to use that and not this.
54
weak int _mmap_js(size_t length,
55
int prot,
56
int flags,
57
int fd,
58
off_t offset,
59
int* allocated,
60
void** addr) {
61
return -ENOSYS;
62
}
63
64
weak int _munmap_js(
65
intptr_t addr, size_t length, int prot, int flags, int fd, off_t offset) {
66
return -ENOSYS;
67
}
68
69
weak int _poll_js(void *fds, int nfds, int timeout, void* ctx, void* arg) {
70
return -ENOSYS;
71
}
72
73
// open(), etc. - we just support the standard streams, with no
74
// corner case error checking; everything else is not permitted.
75
// TODO: full file support for WASI, or an option for it
76
// open()
77
weak int __syscall_openat(int dirfd, intptr_t path, int flags, ...) {
78
if (!strcmp((const char*)path, "/dev/stdin")) {
79
return STDIN_FILENO;
80
}
81
if (!strcmp((const char*)path, "/dev/stdout")) {
82
return STDOUT_FILENO;
83
}
84
if (!strcmp((const char*)path, "/dev/stderr")) {
85
return STDERR_FILENO;
86
}
87
return -EPERM;
88
}
89
90
weak int __syscall_ioctl(int fd, int op, ...) {
91
return -ENOSYS;
92
}
93
94
weak int __syscall_fcntl64(int fd, int cmd, ...) {
95
return -ENOSYS;
96
}
97
98
weak int __syscall_fstat64(int fd, intptr_t buf) {
99
return -ENOSYS;
100
}
101
102
weak int __syscall_stat64(intptr_t path, intptr_t buf) {
103
return -ENOSYS;
104
}
105
106
weak int __syscall_dup(int fd) {
107
return -ENOSYS;
108
}
109
110
weak int __syscall_mkdirat(int dirfd, intptr_t path, int mode) {
111
return -ENOSYS;
112
}
113
114
weak int __syscall_newfstatat(int dirfd, intptr_t path, intptr_t buf, int flags) {
115
return -ENOSYS;
116
}
117
118
weak int __syscall_lstat64(intptr_t path, intptr_t buf) {
119
return -ENOSYS;
120
}
121
122
// Emscripten additions
123
124
size_t emscripten_get_heap_max() {
125
// In standalone mode we don't have any wasm instructions to access the max
126
// memory size so the best we can do (without calling an import) is return
127
// the current heap size.
128
return emscripten_get_heap_size();
129
}
130
131
int emscripten_resize_heap(size_t size) {
132
#if defined(EMSCRIPTEN_MEMORY_GROWTH)
133
size_t old_size = __builtin_wasm_memory_size(0) * WASM_PAGE_SIZE;
134
assert(old_size < size);
135
ssize_t diff = (size - old_size + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE;
136
size_t result = __builtin_wasm_memory_grow(0, diff);
137
if (result != (size_t)-1) {
138
#if !defined(EMSCRIPTEN_PURE_WASI)
139
// Success, update JS (see https://github.com/WebAssembly/WASI/issues/82)
140
emscripten_notify_memory_growth(0);
141
#endif
142
return 1;
143
}
144
#endif
145
return 0;
146
}
147
148
// Call clock_gettime with a particular clock and return the result in ms.
149
static double clock_gettime_ms(clockid_t clock) {
150
struct timespec ts;
151
if (clock_gettime(clock, &ts)) {
152
return 0;
153
}
154
return (double)ts.tv_sec * 1000 + (double)ts.tv_nsec / 1000000;
155
}
156
157
weak double emscripten_get_now(void) {
158
return clock_gettime_ms(CLOCK_MONOTONIC);
159
}
160
161
weak double emscripten_date_now(void) {
162
return clock_gettime_ms(CLOCK_REALTIME);
163
}
164
165
// C++ ABI
166
167
#if EMSCRIPTEN_NOCATCH
168
// When exception catching is disabled, we stub out calls to `__cxa_throw`.
169
// Otherwise, `__cxa_throw` will be imported from the host.
170
void __cxa_throw(void* ptr, void* type, void* destructor) {
171
abort();
172
}
173
#endif
174
175
// WasmFS integration. We stub out file preloading and such, that are not
176
// expected to work anyhow.
177
178
size_t _wasmfs_get_num_preloaded_files() { return 0; }
179
180
size_t _wasmfs_get_num_preloaded_dirs() { return 0; }
181
182
int _wasmfs_get_preloaded_file_size(int index) { return 0; }
183
184
int _wasmfs_get_preloaded_file_mode(int index) { return 0; }
185
186
void _wasmfs_copy_preloaded_file_data(int index, void* buffer) {}
187
188
void _wasmfs_get_preloaded_parent_path(int index, void* buffer) {}
189
190
void _wasmfs_get_preloaded_child_path(int index, void* buffer) {}
191
192
void _wasmfs_get_preloaded_path_name(int index, void* buffer) {}
193
194
// Import the VM's fd_write under a different name. Then we can interpose in
195
// between it and WasmFS's fd_write. That is, libc calls fd_write, which WasmFS
196
// implements. And WasmFS will forward actual writing to stdout/stderr to the
197
// VM's fd_write. (This allows WasmFS to do work in the middle, for example, it
198
// could support embedded files and other functionality.)
199
__attribute__((import_module("wasi_snapshot_preview1"),
200
import_name("fd_write"))) __wasi_errno_t
201
imported__wasi_fd_write(__wasi_fd_t fd,
202
const __wasi_ciovec_t* iovs,
203
size_t iovs_len,
204
__wasi_size_t* nwritten);
205
206
// Write a buffer + a newline.
207
static void wasi_writeln_n(__wasi_fd_t fd, const char* buffer, size_t len) {
208
struct __wasi_ciovec_t iovs[2];
209
iovs[0].buf = (uint8_t*)buffer;
210
iovs[0].buf_len = len;
211
iovs[1].buf = (uint8_t*)"\n";
212
iovs[1].buf_len = 1;
213
__wasi_size_t nwritten;
214
imported__wasi_fd_write(fd, iovs, 2, &nwritten);
215
}
216
217
static void wasi_writeln(__wasi_fd_t fd, const char* buffer) {
218
return wasi_writeln_n(fd, buffer, strlen(buffer));
219
}
220
221
weak void emscripten_out(const char* text) { wasi_writeln(1, text); }
222
223
weak void emscripten_err(const char* text) { wasi_writeln(2, text); }
224
225
weak void emscripten_dbg(const char* text) { wasi_writeln(2, text); }
226
227
weak void emscripten_outn(const char* text, size_t len) {
228
wasi_writeln_n(1, text, len);
229
}
230
231
weak void emscripten_errn(const char* text, size_t len) {
232
wasi_writeln_n(2, text, len);
233
}
234
235
weak void emscripten_dbgn(const char* text, size_t len) {
236
wasi_writeln_n(2, text, len);
237
}
238
239
__attribute__((import_module("wasi_snapshot_preview1"),
240
import_name("fd_read"))) __wasi_errno_t
241
imported__wasi_fd_read(__wasi_fd_t fd,
242
const __wasi_ciovec_t* iovs,
243
size_t iovs_len,
244
__wasi_size_t* nread);
245
246
int _wasmfs_stdin_get_char(void) {
247
char c;
248
struct __wasi_ciovec_t iov;
249
iov.buf = (uint8_t*)&c;
250
iov.buf_len = 1;
251
__wasi_size_t nread;
252
imported__wasi_fd_read(0, &iov, 1, &nread);
253
if (nread == 0) {
254
return -1;
255
}
256
return c;
257
}
258
259
// In the non-standalone build we define this helper function in JS to avoid
260
// signature mismatch issues.
261
// See: https://github.com/emscripten-core/posixtestsuite/issues/6
262
void __call_sighandler(sighandler_t handler, int sig) {
263
handler(sig);
264
}
265
266
int _setitimer_js(int which, double timeout) {
267
// There is no API to let us set timers in standalone mode atm. Return an
268
// error.
269
errno = ENOTSUP;
270
return -1;
271
}
272
273
weak uintptr_t emscripten_stack_snapshot(void) {
274
return 0;
275
}
276
277
weak uint32_t emscripten_stack_unwind_buffer(uintptr_t pc,
278
uintptr_t* buffer,
279
uint32_t depth) {
280
return 0;
281
}
282
283
weak const char* emscripten_pc_get_function(uintptr_t pc) {
284
return NULL;
285
}
286
287
weak const char* emscripten_pc_get_file(uintptr_t pc) {
288
return NULL;
289
}
290
291
weak int emscripten_pc_get_line(uintptr_t pc) {
292
return 0;
293
}
294
295
weak int emscripten_pc_get_column(uintptr_t pc) {
296
return 0;
297
}
298
299
weak void* emscripten_return_address(int level) {
300
return NULL;
301
}
302
303
weak int _emscripten_sanitizer_use_colors(void) {
304
return 1;
305
}
306
307
weak char* _emscripten_sanitizer_get_option(const char* name) {
308
return strdup("");
309
}
310
311
weak void _emscripten_get_progname(char* buf, int length) {
312
strncpy(buf, "<unknown>", length);
313
}
314
315
weak void _emscripten_runtime_keepalive_clear() {}
316
317
void __throw_exception_with_stack_trace(_Unwind_Exception* exception_object) {
318
_Unwind_RaiseException(exception_object);
319
}
320
321