@scriptc/runtime 0.0.25 → 0.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/scr_array.c +1 -1
- package/src/scr_assert.c +4 -4
- package/src/scr_async.c +235 -6
- package/src/scr_bytes.c +1 -1
- package/src/scr_child.c +2 -2
- package/src/scr_closure.c +2 -2
- package/src/scr_console.c +1 -1
- package/src/scr_cycle.c +14 -14
- package/src/scr_error.c +3 -3
- package/src/scr_events.c +48 -2
- package/src/scr_events_emitter.c +7 -7
- package/src/scr_exception.c +22 -12
- package/src/scr_http.c +1 -0
- package/src/scr_inspect.c +10 -10
- package/src/scr_island.c +8 -4
- package/src/scr_json.c +14 -14
- package/src/scr_lib.c +104 -28
- package/src/scr_library.c +33 -13
- package/src/scr_map.c +1 -1
- package/src/scr_musl.c +274 -0
- package/src/scr_net.c +118 -3
- package/src/scr_object.c +1 -1
- package/src/scr_regex.c +2 -2
- package/src/scr_runtime.h +82 -25
- package/src/scr_string.c +4 -4
- package/src/scr_symbol.c +1 -1
- package/src/scr_tls.c +22 -0
- package/src/scr_union.c +1 -1
- package/vendor/README.md +8 -0
package/src/scr_lib.c
CHANGED
|
@@ -104,14 +104,14 @@ extern char **environ; /* env snapshot (scr_env_pairs) */
|
|
|
104
104
|
|
|
105
105
|
/* ── process ─────────────────────────────────────────────────────────── */
|
|
106
106
|
|
|
107
|
-
static int scr_lib_argc = 0;
|
|
108
|
-
static char **scr_lib_argv = NULL;
|
|
109
|
-
static ScrArr *scr_argv_arr = NULL; /* interned process.argv */
|
|
110
|
-
static ScrStr *scr_platform_str = NULL; /* interned process.platform */
|
|
111
|
-
static ScrStr *scr_exec_path_str = NULL; /* interned process.execPath */
|
|
112
|
-
static ScrStr *scr_arch_str = NULL; /* interned process.arch */
|
|
113
|
-
static ScrStr *scr_versions_node_str = NULL; /* interned process.versions.node */
|
|
114
|
-
static ScrStr *scr_versions_openssl_str = NULL; /* interned process.versions.openssl */
|
|
107
|
+
static SCR_TL int scr_lib_argc = 0;
|
|
108
|
+
static SCR_TL char **scr_lib_argv = NULL;
|
|
109
|
+
static SCR_TL ScrArr *scr_argv_arr = NULL; /* interned process.argv */
|
|
110
|
+
static SCR_TL ScrStr *scr_platform_str = NULL; /* interned process.platform */
|
|
111
|
+
static SCR_TL ScrStr *scr_exec_path_str = NULL; /* interned process.execPath */
|
|
112
|
+
static SCR_TL ScrStr *scr_arch_str = NULL; /* interned process.arch */
|
|
113
|
+
static SCR_TL ScrStr *scr_versions_node_str = NULL; /* interned process.versions.node */
|
|
114
|
+
static SCR_TL ScrStr *scr_versions_openssl_str = NULL; /* interned process.versions.openssl */
|
|
115
115
|
|
|
116
116
|
static void scr_lib_cleanup(void) {
|
|
117
117
|
scr_arr_release(scr_argv_arr);
|
|
@@ -175,6 +175,8 @@ ScrStr *scr_process_platform(void) {
|
|
|
175
175
|
scr_platform_str = scr_str_new("darwin", 6);
|
|
176
176
|
#elif defined(__linux__)
|
|
177
177
|
scr_platform_str = scr_str_new("linux", 5);
|
|
178
|
+
#elif defined(__wasi__)
|
|
179
|
+
scr_platform_str = scr_str_new("wasi", 4);
|
|
178
180
|
#elif defined(_WIN32)
|
|
179
181
|
scr_platform_str = scr_str_new("win32", 5);
|
|
180
182
|
#else
|
|
@@ -188,7 +190,11 @@ ScrStr *scr_process_platform(void) {
|
|
|
188
190
|
* Node spells its own build's arch. Interned like process.platform. */
|
|
189
191
|
ScrStr *scr_process_arch(void) {
|
|
190
192
|
if (!scr_arch_str) {
|
|
191
|
-
#if defined(
|
|
193
|
+
#if defined(__wasm32__)
|
|
194
|
+
scr_arch_str = scr_str_new("wasm32", 6);
|
|
195
|
+
#elif defined(__wasm64__)
|
|
196
|
+
scr_arch_str = scr_str_new("wasm64", 6);
|
|
197
|
+
#elif defined(__aarch64__) || defined(_M_ARM64)
|
|
192
198
|
scr_arch_str = scr_str_new("arm64", 5);
|
|
193
199
|
#elif defined(__x86_64__) || defined(_M_X64)
|
|
194
200
|
scr_arch_str = scr_str_new("x64", 3);
|
|
@@ -350,11 +356,11 @@ ScrArr *scr_env_pairs(void) {
|
|
|
350
356
|
|
|
351
357
|
double scr_process_pid(void) { return (double)getpid(); }
|
|
352
358
|
|
|
353
|
-
#
|
|
359
|
+
#if defined(_WIN32) || defined(__wasi__)
|
|
354
360
|
/* No uids/gids exist on Windows: Node's process object simply has no
|
|
355
361
|
* getuid/getgid members there, so a call is the property-access TypeError
|
|
356
362
|
* below — thrown catchably, exactly what `process.getuid()` does under
|
|
357
|
-
* Windows Node. */
|
|
363
|
+
* Windows Node. WASI has no uid/gid process model either. */
|
|
358
364
|
double scr_process_getuid(void) {
|
|
359
365
|
scr_throw_error_msg(SCR_ERR_TYPE, "process.getuid is not a function", 32);
|
|
360
366
|
return 0;
|
|
@@ -532,6 +538,14 @@ static int scr_win_kill(int pid, int sig) {
|
|
|
532
538
|
return 0;
|
|
533
539
|
}
|
|
534
540
|
#define scr_sys_kill(pid, sig) scr_win_kill((int)(pid), (sig))
|
|
541
|
+
#elif defined(__wasi__)
|
|
542
|
+
static int scr_wasi_kill(int pid, int sig) {
|
|
543
|
+
(void)pid;
|
|
544
|
+
(void)sig;
|
|
545
|
+
errno = ENOSYS;
|
|
546
|
+
return -1;
|
|
547
|
+
}
|
|
548
|
+
#define scr_sys_kill(pid, sig) scr_wasi_kill((int)(pid), (sig))
|
|
535
549
|
#else
|
|
536
550
|
#define scr_sys_kill(pid, sig) kill((pid_t)(pid), (sig))
|
|
537
551
|
#endif
|
|
@@ -689,6 +703,27 @@ ScrStr *scr_os_tmpdir(void) {
|
|
|
689
703
|
if (len > 1 && (buf[len - 1] == '\\' || buf[len - 1] == '/')) len--;
|
|
690
704
|
return scr_str_new(buf, len);
|
|
691
705
|
}
|
|
706
|
+
#elif defined(__wasi__)
|
|
707
|
+
/* WASI has an inherited environment but no passwd database, uname, or
|
|
708
|
+
* physical-memory query. Keep the useful environment-backed answers and
|
|
709
|
+
* spell the platform explicitly for the rest. */
|
|
710
|
+
ScrStr *scr_os_homedir(void) {
|
|
711
|
+
const char *home = getenv("HOME");
|
|
712
|
+
return scr_str_new(home ? home : "", home ? strlen(home) : 0);
|
|
713
|
+
}
|
|
714
|
+
ScrStr *scr_os_user_name(void) {
|
|
715
|
+
const char *user = getenv("USER");
|
|
716
|
+
return scr_str_new(user ? user : "", user ? strlen(user) : 0);
|
|
717
|
+
}
|
|
718
|
+
ScrStr *scr_os_user_shell(void) { return scr_str_new("", 0); }
|
|
719
|
+
ScrStr *scr_os_user_homedir(void) { return scr_os_homedir(); }
|
|
720
|
+
ScrStr *scr_os_release(void) { return scr_str_new("", 0); }
|
|
721
|
+
ScrStr *scr_os_type(void) { return scr_str_new("WASI", 4); }
|
|
722
|
+
double scr_os_totalmem(void) { return 0; }
|
|
723
|
+
/* The guest temp namespace is stable across hosts. `scriptc run` preopens
|
|
724
|
+
* the host's /tmp at this path; other WASI hosts can provide the same
|
|
725
|
+
* capability without leaking a host-specific TMPDIR into the module. */
|
|
726
|
+
ScrStr *scr_os_tmpdir(void) { return scr_str_new("/tmp", 4); }
|
|
692
727
|
#else
|
|
693
728
|
ScrStr *scr_os_homedir(void) {
|
|
694
729
|
/* uv_os_homedir: $HOME when set (even empty is "set" only if non-NULL;
|
|
@@ -1068,8 +1103,27 @@ void scr_process_exit(double code) {
|
|
|
1068
1103
|
* attribute monotonic stamp — the binary's own start, which is what
|
|
1069
1104
|
* "the current Node.js process" means for a compiled program). */
|
|
1070
1105
|
#ifdef _WIN32
|
|
1106
|
+
#if defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
1107
|
+
/* The uptime anchor belongs to the host PROCESS, not to a library
|
|
1108
|
+
* instance. InitOnce keeps the lazy Windows spelling race-free when
|
|
1109
|
+
* several thread instances ask for the clock concurrently. */
|
|
1110
|
+
static INIT_ONCE scr_uptime_once = INIT_ONCE_STATIC_INIT;
|
|
1071
1111
|
static double scr_uptime_t0_ms;
|
|
1112
|
+
static BOOL CALLBACK scr_uptime_anchor_once(PINIT_ONCE once, PVOID param,
|
|
1113
|
+
PVOID *ctx) {
|
|
1114
|
+
(void)once;
|
|
1115
|
+
(void)param;
|
|
1116
|
+
(void)ctx;
|
|
1117
|
+
scr_uptime_t0_ms = (double)GetTickCount64();
|
|
1118
|
+
return TRUE;
|
|
1119
|
+
}
|
|
1120
|
+
static void scr_uptime_anchor_init(void) {
|
|
1121
|
+
InitOnceExecuteOnce(&scr_uptime_once, scr_uptime_anchor_once, NULL, NULL);
|
|
1122
|
+
}
|
|
1123
|
+
#else
|
|
1124
|
+
static SCR_TL double scr_uptime_t0_ms;
|
|
1072
1125
|
static void scr_uptime_anchor_init(void) { scr_uptime_t0_ms = (double)GetTickCount64(); }
|
|
1126
|
+
#endif
|
|
1073
1127
|
static double scr_uptime_now_ms(void) { return (double)GetTickCount64(); }
|
|
1074
1128
|
#else
|
|
1075
1129
|
#include <sys/resource.h>
|
|
@@ -1077,6 +1131,10 @@ static double scr_uptime_now_ms(void) { return (double)GetTickCount64(); }
|
|
|
1077
1131
|
#ifdef __APPLE__
|
|
1078
1132
|
#include <mach/mach.h>
|
|
1079
1133
|
#endif
|
|
1134
|
+
/* A load-time, process-wide anchor: the constructor runs on only the
|
|
1135
|
+
* initial thread, while thread-instanced archives are entered from worker
|
|
1136
|
+
* threads whose TLS slots would otherwise stay zero. It is immutable once
|
|
1137
|
+
* main starts, so sharing it adds no cross-instance mutable state. */
|
|
1080
1138
|
static double scr_uptime_t0_ms;
|
|
1081
1139
|
static double scr_uptime_now_ms(void) {
|
|
1082
1140
|
struct timespec ts;
|
|
@@ -1089,7 +1147,9 @@ __attribute__((constructor)) static void scr_uptime_anchor_init(void) {
|
|
|
1089
1147
|
#endif
|
|
1090
1148
|
|
|
1091
1149
|
double scr_process_uptime(void) {
|
|
1092
|
-
#
|
|
1150
|
+
#if defined(_WIN32) && defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
1151
|
+
scr_uptime_anchor_init();
|
|
1152
|
+
#elif defined(_WIN32)
|
|
1093
1153
|
if (scr_uptime_t0_ms == 0) scr_uptime_anchor_init();
|
|
1094
1154
|
#endif
|
|
1095
1155
|
return (scr_uptime_now_ms() - scr_uptime_t0_ms) / 1000.0;
|
|
@@ -1099,7 +1159,9 @@ double scr_process_uptime(void) {
|
|
|
1099
1159
|
* start (Node's timeOrigin anchor), fractional — the same monotonic
|
|
1100
1160
|
* clock and anchor as uptime, in Node's performance.now units. */
|
|
1101
1161
|
double scr_perf_now(void) {
|
|
1102
|
-
#
|
|
1162
|
+
#if defined(_WIN32) && defined(SCR_LIB) && defined(SCR_THREAD_INSTANCES)
|
|
1163
|
+
scr_uptime_anchor_init();
|
|
1164
|
+
#elif defined(_WIN32)
|
|
1103
1165
|
if (scr_uptime_t0_ms == 0) scr_uptime_anchor_init();
|
|
1104
1166
|
#endif
|
|
1105
1167
|
return scr_uptime_now_ms() - scr_uptime_t0_ms;
|
|
@@ -1226,7 +1288,7 @@ double scr_thread_cpu_system_diff(double prev) { return scr_thread_cpu_system()
|
|
|
1226
1288
|
* Darwin's bytes by 1024; the rest are getrusage's own counters, zero
|
|
1227
1289
|
* where the platform never fills them). */
|
|
1228
1290
|
double scr_process_rusage(double idx) {
|
|
1229
|
-
#
|
|
1291
|
+
#if defined(_WIN32) || defined(__wasi__)
|
|
1230
1292
|
/* uv fills only the CPU times and page-fault/maxRSS slice on Windows;
|
|
1231
1293
|
* everything else answers 0 — Node's own shape there. */
|
|
1232
1294
|
switch ((int)idx) {
|
|
@@ -1318,7 +1380,7 @@ double scr_available_memory(void) {
|
|
|
1318
1380
|
/* process._exiting — true once the exit sequence began (set above and by
|
|
1319
1381
|
* scr_run_exit_listeners in scr_events.c; the flag lives HERE so reading
|
|
1320
1382
|
* it never forces the events unit into the link). */
|
|
1321
|
-
bool scr_process_in_exit = false;
|
|
1383
|
+
SCR_TL bool scr_process_in_exit = false;
|
|
1322
1384
|
|
|
1323
1385
|
bool scr_process_exiting(void) { return scr_process_in_exit; }
|
|
1324
1386
|
|
|
@@ -1336,6 +1398,11 @@ double scr_process_umask(double mask) {
|
|
|
1336
1398
|
_umask_s((int)mask, &prev);
|
|
1337
1399
|
}
|
|
1338
1400
|
return (double)prev;
|
|
1401
|
+
#elif defined(__wasi__)
|
|
1402
|
+
static SCR_TL mode_t current = 022;
|
|
1403
|
+
mode_t prev = current;
|
|
1404
|
+
if (mask >= 0) current = (mode_t)mask;
|
|
1405
|
+
return (double)prev;
|
|
1339
1406
|
#else
|
|
1340
1407
|
mode_t prev;
|
|
1341
1408
|
if (mask < 0) {
|
|
@@ -1359,7 +1426,7 @@ void scr_process_chdir(ScrStr *dir) {
|
|
|
1359
1426
|
/* net's process-wide happy-eyeballs attempt budget (Node's
|
|
1360
1427
|
* getDefaultAutoSelectFamilyAttemptTimeout pair, default 250ms). Lives in
|
|
1361
1428
|
* the core unit so the knob never forces scr_net.c into the link. */
|
|
1362
|
-
static double scr_net_autosel_timeout_ms = 250;
|
|
1429
|
+
static SCR_TL double scr_net_autosel_timeout_ms = 250;
|
|
1363
1430
|
|
|
1364
1431
|
double scr_net_get_autosel_timeout(void) { return scr_net_autosel_timeout_ms; }
|
|
1365
1432
|
|
|
@@ -1653,9 +1720,10 @@ void scr_fs_chmod(ScrStr *path, double mode) {
|
|
|
1653
1720
|
}
|
|
1654
1721
|
|
|
1655
1722
|
void scr_fs_chown(ScrStr *path, double uid, double gid) {
|
|
1656
|
-
#
|
|
1723
|
+
#if defined(_WIN32) || defined(__wasi__)
|
|
1657
1724
|
/* libuv's uv_fs_chown on Windows is an unconditional no-op success —
|
|
1658
|
-
* Node's chownSync "works" and changes nothing there;
|
|
1725
|
+
* Node's chownSync "works" and changes nothing there; WASI likewise has
|
|
1726
|
+
* no ownership model. */
|
|
1659
1727
|
(void)path; (void)uid; (void)gid;
|
|
1660
1728
|
#else
|
|
1661
1729
|
/* Node passes the ids straight to chown(2); -1 is the POSIX "leave
|
|
@@ -1863,7 +1931,7 @@ static bool scr_fs_write_fd_valid(double fd) {
|
|
|
1863
1931
|
* call, preserving any signal that was already pending. */
|
|
1864
1932
|
static ssize_t scr_fs_write_once(int fd, const void *data, size_t length,
|
|
1865
1933
|
bool positioned, double position) {
|
|
1866
|
-
#
|
|
1934
|
+
#if defined(_WIN32) || defined(__wasi__)
|
|
1867
1935
|
return positioned
|
|
1868
1936
|
? scr_fs_pwrite(fd, data, length, position)
|
|
1869
1937
|
: write(fd, data, length);
|
|
@@ -2520,23 +2588,23 @@ void scr_fs_rm_opts_retry(ScrStr *path, bool recursive, bool force, double max_r
|
|
|
2520
2588
|
scr_str_release(f.path);
|
|
2521
2589
|
}
|
|
2522
2590
|
|
|
2523
|
-
#
|
|
2524
|
-
/* No mkdtemp in the CRT: libuv's own fallback shape — six random
|
|
2591
|
+
#if defined(_WIN32) || defined(__wasi__)
|
|
2592
|
+
/* No mkdtemp in the Windows CRT or WASI libc: libuv's own fallback shape — six random
|
|
2525
2593
|
* [a-z0-9] name characters from the CSPRNG, retried on EEXIST. */
|
|
2526
|
-
static char *
|
|
2594
|
+
static char *scr_portable_mkdtemp(char *tmpl) {
|
|
2527
2595
|
static const char cs[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
2528
2596
|
size_t len = strlen(tmpl);
|
|
2529
2597
|
for (int tries = 0; tries < 32; tries++) {
|
|
2530
2598
|
unsigned char r[6];
|
|
2531
2599
|
arc4random_buf(r, sizeof r);
|
|
2532
2600
|
for (size_t i = 0; i < 6; i++) tmpl[len - 6 + i] = cs[r[i] % 36];
|
|
2533
|
-
if (
|
|
2601
|
+
if (scr_sys_mkdir(tmpl, 0777) == 0) return tmpl;
|
|
2534
2602
|
if (errno != EEXIST) break;
|
|
2535
2603
|
}
|
|
2536
2604
|
memcpy(tmpl + len - 6, "XXXXXX", 6); /* the error message shows the template */
|
|
2537
2605
|
return NULL;
|
|
2538
2606
|
}
|
|
2539
|
-
#define mkdtemp
|
|
2607
|
+
#define mkdtemp scr_portable_mkdtemp
|
|
2540
2608
|
#endif
|
|
2541
2609
|
|
|
2542
2610
|
ScrStr *scr_fs_mkdtemp(ScrStr *prefix) {
|
|
@@ -2688,6 +2756,8 @@ double scr_process_columns(double fd) {
|
|
|
2688
2756
|
CONSOLE_SCREEN_BUFFER_INFO info;
|
|
2689
2757
|
if (h == INVALID_HANDLE_VALUE || !GetConsoleScreenBufferInfo(h, &info)) return -1;
|
|
2690
2758
|
return (double)(info.srWindow.Right - info.srWindow.Left + 1);
|
|
2759
|
+
#elif defined(__wasi__)
|
|
2760
|
+
return -1;
|
|
2691
2761
|
#else
|
|
2692
2762
|
struct winsize ws;
|
|
2693
2763
|
if (ioctl((int)fd, TIOCGWINSZ, &ws) != 0) return -1;
|
|
@@ -2702,8 +2772,8 @@ double scr_process_columns(double fd) {
|
|
|
2702
2772
|
* NON-TTY stdin: Node's process.stdin is a Socket with no setRawMode
|
|
2703
2773
|
* member at all, so the call throws Node's exact catchable TypeError. */
|
|
2704
2774
|
#ifdef _WIN32
|
|
2705
|
-
static DWORD scr_stdin_cooked;
|
|
2706
|
-
static bool scr_stdin_cooked_saved = false;
|
|
2775
|
+
static SCR_TL DWORD scr_stdin_cooked;
|
|
2776
|
+
static SCR_TL bool scr_stdin_cooked_saved = false;
|
|
2707
2777
|
|
|
2708
2778
|
void scr_process_stdin_set_raw_mode(bool raw) {
|
|
2709
2779
|
if (!isatty(0)) {
|
|
@@ -2728,9 +2798,15 @@ void scr_process_stdin_set_raw_mode(bool raw) {
|
|
|
2728
2798
|
(void)SetConsoleMode(h, scr_stdin_cooked);
|
|
2729
2799
|
}
|
|
2730
2800
|
}
|
|
2801
|
+
#elif defined(__wasi__)
|
|
2802
|
+
void scr_process_stdin_set_raw_mode(bool raw) {
|
|
2803
|
+
(void)raw;
|
|
2804
|
+
const char msg[] = "process.stdin.setRawMode is not a function";
|
|
2805
|
+
scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1);
|
|
2806
|
+
}
|
|
2731
2807
|
#else
|
|
2732
|
-
static struct termios scr_stdin_cooked;
|
|
2733
|
-
static bool scr_stdin_cooked_saved = false;
|
|
2808
|
+
static SCR_TL struct termios scr_stdin_cooked;
|
|
2809
|
+
static SCR_TL bool scr_stdin_cooked_saved = false;
|
|
2734
2810
|
|
|
2735
2811
|
void scr_process_stdin_set_raw_mode(bool raw) {
|
|
2736
2812
|
if (!isatty(0)) {
|
package/src/scr_library.c
CHANGED
|
@@ -10,6 +10,24 @@
|
|
|
10
10
|
* profile-agnostic and the program TU carries every profile-named symbol —
|
|
11
11
|
* one place for the conformance symbol audit to look.
|
|
12
12
|
*
|
|
13
|
+
* Multi-instance processes (the profile's abi.localize_runtime): the
|
|
14
|
+
* archive build demotes this file's externals — and every other runtime
|
|
15
|
+
* internal — to LOCAL symbols, so each linked archive carries its own
|
|
16
|
+
* private copy of all the state here: its own sink registration, poison
|
|
17
|
+
* flag, arena, and entry-symbol slot. Sinks therefore register per
|
|
18
|
+
* instance, and a trap poisons only the instance it fired in. Nothing in
|
|
19
|
+
* this file is thread-aware; the embedder contract is one thread per
|
|
20
|
+
* instance (an instance is never entered from two threads).
|
|
21
|
+
*
|
|
22
|
+
* Thread-instanced archives (the profile's abi.instance_per_thread) take
|
|
23
|
+
* the same story one level down: SCR_TL moves this file's state — and
|
|
24
|
+
* every other mutable static in the archive — into thread-local storage,
|
|
25
|
+
* so ONE linked archive serves one independent instance per embedder
|
|
26
|
+
* thread. A thread registers its own sink and calls the init entry before
|
|
27
|
+
* serving; its trap poisons only its own instance while sibling threads'
|
|
28
|
+
* instances keep answering. The one-thread-per-instance contract is
|
|
29
|
+
* unchanged — the calling thread IS the instance selector.
|
|
30
|
+
*
|
|
13
31
|
* State after a sink call: none is legal. The trap fired mid-operation with
|
|
14
32
|
* no unwinding — heap, arena, and collector state are unspecified; the library
|
|
15
33
|
* is POISONED. Every runtime-touching entry prologue aborts on the flag
|
|
@@ -23,9 +41,9 @@
|
|
|
23
41
|
|
|
24
42
|
/* ── sink registration + poison ───────────────────────────────────────── */
|
|
25
43
|
|
|
26
|
-
static ScrLibSinkFn scr_library_sink = NULL;
|
|
27
|
-
static void *scr_library_sink_ctx = NULL;
|
|
28
|
-
static bool scr_library_poisoned = false;
|
|
44
|
+
static SCR_TL ScrLibSinkFn scr_library_sink = NULL;
|
|
45
|
+
static SCR_TL void *scr_library_sink_ctx = NULL;
|
|
46
|
+
static SCR_TL bool scr_library_poisoned = false;
|
|
29
47
|
|
|
30
48
|
void scr_library_set_sink(ScrLibSinkFn fn, void *ctx) {
|
|
31
49
|
/* Latest registration wins; re-registration is permitted before a trap.
|
|
@@ -62,10 +80,12 @@ void scr_library_set_sink(ScrLibSinkFn fn, void *ctx) {
|
|
|
62
80
|
|
|
63
81
|
/* The current-entry slot: every generated entry's prologue records its
|
|
64
82
|
* external symbol before dispatching into core code. A single static slot
|
|
65
|
-
* is sound — exactly one core is live per
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
|
|
83
|
+
* is sound — exactly one core is live per copy of this state (the sole
|
|
84
|
+
* core in a classic process; each archive's own instance under
|
|
85
|
+
* abi.localize_runtime, where this slot is a per-instance local), entries
|
|
86
|
+
* never nest, and a trap can only fire while an entry is on the stack.
|
|
87
|
+
* NULL (never entered) renders as the empty symbol field. */
|
|
88
|
+
static SCR_TL const char *scr_library_entry_symbol = NULL;
|
|
69
89
|
|
|
70
90
|
/* Detected-trap classification: the runtime's trap sites self-classify
|
|
71
91
|
* through their message conventions (the exact bytes the executable lane
|
|
@@ -103,7 +123,7 @@ static _Noreturn void scr_library_trap_deliver(const char *msg, size_t len, uint
|
|
|
103
123
|
* no malloc on the failure path; text truncates before structure ever
|
|
104
124
|
* would (codes and symbols are short; an oversized remediation drops
|
|
105
125
|
* whole, never split). */
|
|
106
|
-
static char buf[2048];
|
|
126
|
+
static SCR_TL char buf[2048];
|
|
107
127
|
const char *code = scr_library_trap_code(msg, len);
|
|
108
128
|
const char *text = msg;
|
|
109
129
|
size_t text_len = len;
|
|
@@ -168,7 +188,7 @@ __attribute__((noinline)) _Noreturn void scr_trap_len(const char *msg, size_t le
|
|
|
168
188
|
}
|
|
169
189
|
|
|
170
190
|
__attribute__((noinline)) _Noreturn void scr_trap_fmt(const char *fmt, ...) {
|
|
171
|
-
static char buf[512]; /* no malloc on the invariant-failure path */
|
|
191
|
+
static SCR_TL char buf[512]; /* no malloc on the invariant-failure path */
|
|
172
192
|
va_list ap;
|
|
173
193
|
va_start(ap, fmt);
|
|
174
194
|
int n = vsnprintf(buf, sizeof buf, fmt, ap);
|
|
@@ -202,8 +222,8 @@ typedef struct {
|
|
|
202
222
|
bool is_str; /* ScrStr vs ScrBytes — picks the release */
|
|
203
223
|
} ScrCoreArenaEnt;
|
|
204
224
|
|
|
205
|
-
static ScrCoreArenaEnt *scr_library_arena = NULL;
|
|
206
|
-
static size_t scr_library_arena_n = 0, scr_library_arena_cap = 0;
|
|
225
|
+
static SCR_TL ScrCoreArenaEnt *scr_library_arena = NULL;
|
|
226
|
+
static SCR_TL size_t scr_library_arena_n = 0, scr_library_arena_cap = 0;
|
|
207
227
|
|
|
208
228
|
static void scr_library_arena_keep(void *v, bool is_str) {
|
|
209
229
|
if (scr_library_arena_n == scr_library_arena_cap) {
|
|
@@ -285,8 +305,8 @@ void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len) {
|
|
|
285
305
|
* satisfied because the entry persists. */
|
|
286
306
|
|
|
287
307
|
#define SCR_LIB_MAX_RESETS 32
|
|
288
|
-
static void (*scr_library_resets[SCR_LIB_MAX_RESETS])(void);
|
|
289
|
-
static size_t scr_library_nresets = 0;
|
|
308
|
+
static SCR_TL void (*scr_library_resets[SCR_LIB_MAX_RESETS])(void);
|
|
309
|
+
static SCR_TL size_t scr_library_nresets = 0;
|
|
290
310
|
|
|
291
311
|
void scr_library_register_reset(void (*fn)(void)) {
|
|
292
312
|
for (size_t i = 0; i < scr_library_nresets; i++) {
|
package/src/scr_map.c
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
/* Live heap-map count for the RC audit lane (-DSCR_RC_AUDIT); same contract
|
|
25
25
|
* as scr_str_live_count in scr_string.c. */
|
|
26
26
|
#ifdef SCR_RC_AUDIT
|
|
27
|
-
static long scr_live_maps = 0;
|
|
27
|
+
static SCR_TL long scr_live_maps = 0;
|
|
28
28
|
long scr_map_live_count(void) { return scr_live_maps; }
|
|
29
29
|
#endif
|
|
30
30
|
|
package/src/scr_musl.c
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/* musl libc shim — compiled into linux-musl target builds only (cc.ts adds
|
|
2
|
+
* this TU together with -DSCR_MUSL). musl deliberately provides no libc
|
|
3
|
+
* identification macro, so the target-selected project macro is the guard.
|
|
4
|
+
*
|
|
5
|
+
* The x86_64 ucontext implementation below is derived from libucontext
|
|
6
|
+
* commit 49e671dd52ff6791295d8161ad3b6da7dc5f6f9d:
|
|
7
|
+
* https://github.com/kaniini/libucontext
|
|
8
|
+
*
|
|
9
|
+
* Copyright (c) 2018-2025 Ariadne Conill <ariadne@dereferenced.org>
|
|
10
|
+
*
|
|
11
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
12
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
13
|
+
* copyright notice and this permission notice appear in all copies.
|
|
14
|
+
*
|
|
15
|
+
* This software is provided 'as is' and without any warranty, express or
|
|
16
|
+
* implied. In no event shall the authors be liable for any damages arising
|
|
17
|
+
* from the use of this software. */
|
|
18
|
+
#ifdef SCR_MUSL
|
|
19
|
+
|
|
20
|
+
#include "scr_runtime.h"
|
|
21
|
+
|
|
22
|
+
#include <errno.h>
|
|
23
|
+
#include <stdlib.h>
|
|
24
|
+
#include <sys/random.h>
|
|
25
|
+
#ifndef SCR_LIB
|
|
26
|
+
#include <stdarg.h>
|
|
27
|
+
#include <ucontext.h>
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#if !defined(__x86_64__)
|
|
31
|
+
#error "scriptc's musl runtime currently supports x86_64 only"
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
/* The scriptc runtime uses arc4random_buf as its infallible CSPRNG contract.
|
|
35
|
+
* Linux getrandom has the same kernel source and needs neither mutable state
|
|
36
|
+
* nor an fd. Retry interrupts and short reads; any other failure enters the
|
|
37
|
+
* runtime trap funnel rather than returning predictable or partially
|
|
38
|
+
* initialized bytes. Executables still print and abort there, while library
|
|
39
|
+
* artifacts deliver the failure to their registered panic sink. */
|
|
40
|
+
void arc4random_buf(void *buf, size_t n) {
|
|
41
|
+
unsigned char *p = buf;
|
|
42
|
+
while (n > 0) {
|
|
43
|
+
ssize_t got = getrandom(p, n, 0);
|
|
44
|
+
if (got > 0) {
|
|
45
|
+
p += (size_t)got;
|
|
46
|
+
n -= (size_t)got;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (got < 0 && errno == EINTR) continue;
|
|
50
|
+
scr_trap("scriptc: getrandom failed\n");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Library artifacts contain no fibers or event loop, so they need only the
|
|
55
|
+
* CSPRNG shim above and must not acquire context-switching definitions. */
|
|
56
|
+
#ifndef SCR_LIB
|
|
57
|
+
|
|
58
|
+
/* musl exposes the POSIX ucontext types but intentionally omits these legacy
|
|
59
|
+
* functions. scriptc's async/generator fibers need only user-space register
|
|
60
|
+
* swaps; they never use a context to mutate the process signal mask. This is
|
|
61
|
+
* libucontext's fast (non-POSIX-signal-mask) x86_64 implementation, emitted
|
|
62
|
+
* under the standard symbol names that musl leaves unresolved. */
|
|
63
|
+
_Static_assert(offsetof(ucontext_t, uc_mcontext.gregs) == 40,
|
|
64
|
+
"unexpected musl x86_64 ucontext layout");
|
|
65
|
+
_Static_assert(offsetof(ucontext_t, uc_mcontext.fpregs) == 224,
|
|
66
|
+
"unexpected musl x86_64 fpregs layout");
|
|
67
|
+
_Static_assert(offsetof(ucontext_t, __fpregs_mem) == 424,
|
|
68
|
+
"unexpected musl x86_64 fpregs storage layout");
|
|
69
|
+
|
|
70
|
+
/* Keep the assembler independent of whether the sysroot exposes glibc's
|
|
71
|
+
* REG_* spellings as enum constants, self-referential macros, or neither. */
|
|
72
|
+
#undef REG_R8
|
|
73
|
+
#undef REG_R9
|
|
74
|
+
#undef REG_R10
|
|
75
|
+
#undef REG_R11
|
|
76
|
+
#undef REG_R12
|
|
77
|
+
#undef REG_R13
|
|
78
|
+
#undef REG_R14
|
|
79
|
+
#undef REG_R15
|
|
80
|
+
#undef REG_RDI
|
|
81
|
+
#undef REG_RSI
|
|
82
|
+
#undef REG_RBP
|
|
83
|
+
#undef REG_RBX
|
|
84
|
+
#undef REG_RDX
|
|
85
|
+
#undef REG_RAX
|
|
86
|
+
#undef REG_RCX
|
|
87
|
+
#undef REG_RSP
|
|
88
|
+
#undef REG_RIP
|
|
89
|
+
#define REG_R8 0
|
|
90
|
+
#define REG_R9 1
|
|
91
|
+
#define REG_R10 2
|
|
92
|
+
#define REG_R11 3
|
|
93
|
+
#define REG_R12 4
|
|
94
|
+
#define REG_R13 5
|
|
95
|
+
#define REG_R14 6
|
|
96
|
+
#define REG_R15 7
|
|
97
|
+
#define REG_RDI 8
|
|
98
|
+
#define REG_RSI 9
|
|
99
|
+
#define REG_RBP 10
|
|
100
|
+
#define REG_RBX 11
|
|
101
|
+
#define REG_RDX 12
|
|
102
|
+
#define REG_RAX 13
|
|
103
|
+
#define REG_RCX 14
|
|
104
|
+
#define REG_RSP 15
|
|
105
|
+
#define REG_RIP 16
|
|
106
|
+
|
|
107
|
+
#define SCR_STR_INNER(x) #x
|
|
108
|
+
#define SCR_STR(x) SCR_STR_INNER(x)
|
|
109
|
+
#define SCR_UC_GREG(reg) (40 + ((reg) * 8))
|
|
110
|
+
|
|
111
|
+
__asm__(
|
|
112
|
+
".text\n"
|
|
113
|
+
".global getcontext\n"
|
|
114
|
+
"getcontext:\n"
|
|
115
|
+
" movq %r8, " SCR_STR(SCR_UC_GREG(REG_R8)) "(%rdi)\n"
|
|
116
|
+
" movq %r9, " SCR_STR(SCR_UC_GREG(REG_R9)) "(%rdi)\n"
|
|
117
|
+
" movq %r10, " SCR_STR(SCR_UC_GREG(REG_R10)) "(%rdi)\n"
|
|
118
|
+
" movq %r11, " SCR_STR(SCR_UC_GREG(REG_R11)) "(%rdi)\n"
|
|
119
|
+
" movq %r12, " SCR_STR(SCR_UC_GREG(REG_R12)) "(%rdi)\n"
|
|
120
|
+
" movq %r13, " SCR_STR(SCR_UC_GREG(REG_R13)) "(%rdi)\n"
|
|
121
|
+
" movq %r14, " SCR_STR(SCR_UC_GREG(REG_R14)) "(%rdi)\n"
|
|
122
|
+
" movq %r15, " SCR_STR(SCR_UC_GREG(REG_R15)) "(%rdi)\n"
|
|
123
|
+
" movq %rdi, " SCR_STR(SCR_UC_GREG(REG_RDI)) "(%rdi)\n"
|
|
124
|
+
" movq %rsi, " SCR_STR(SCR_UC_GREG(REG_RSI)) "(%rdi)\n"
|
|
125
|
+
" movq %rbp, " SCR_STR(SCR_UC_GREG(REG_RBP)) "(%rdi)\n"
|
|
126
|
+
" movq %rbx, " SCR_STR(SCR_UC_GREG(REG_RBX)) "(%rdi)\n"
|
|
127
|
+
" movq %rdx, " SCR_STR(SCR_UC_GREG(REG_RDX)) "(%rdi)\n"
|
|
128
|
+
" movq %rax, " SCR_STR(SCR_UC_GREG(REG_RAX)) "(%rdi)\n"
|
|
129
|
+
" movq %rcx, " SCR_STR(SCR_UC_GREG(REG_RCX)) "(%rdi)\n"
|
|
130
|
+
" movq (%rsp), %rcx\n"
|
|
131
|
+
" movq %rcx, " SCR_STR(SCR_UC_GREG(REG_RIP)) "(%rdi)\n"
|
|
132
|
+
" leaq 8(%rsp), %rcx\n"
|
|
133
|
+
" movq %rcx, " SCR_STR(SCR_UC_GREG(REG_RSP)) "(%rdi)\n"
|
|
134
|
+
" leaq 424(%rdi), %rcx\n"
|
|
135
|
+
" movq %rcx, 224(%rdi)\n"
|
|
136
|
+
" fnstenv (%rcx)\n"
|
|
137
|
+
" fldenv (%rcx)\n"
|
|
138
|
+
" stmxcsr 448(%rdi)\n"
|
|
139
|
+
" xorl %eax, %eax\n"
|
|
140
|
+
" ret\n"
|
|
141
|
+
|
|
142
|
+
".global setcontext\n"
|
|
143
|
+
"setcontext:\n"
|
|
144
|
+
" movq 224(%rdi), %rcx\n"
|
|
145
|
+
" fldenv (%rcx)\n"
|
|
146
|
+
" ldmxcsr 448(%rdi)\n"
|
|
147
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R8)) "(%rdi), %r8\n"
|
|
148
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R9)) "(%rdi), %r9\n"
|
|
149
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R10)) "(%rdi), %r10\n"
|
|
150
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R11)) "(%rdi), %r11\n"
|
|
151
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R12)) "(%rdi), %r12\n"
|
|
152
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R13)) "(%rdi), %r13\n"
|
|
153
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R14)) "(%rdi), %r14\n"
|
|
154
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R15)) "(%rdi), %r15\n"
|
|
155
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RSI)) "(%rdi), %rsi\n"
|
|
156
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RBP)) "(%rdi), %rbp\n"
|
|
157
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RBX)) "(%rdi), %rbx\n"
|
|
158
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RDX)) "(%rdi), %rdx\n"
|
|
159
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RAX)) "(%rdi), %rax\n"
|
|
160
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RCX)) "(%rdi), %rcx\n"
|
|
161
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RSP)) "(%rdi), %rsp\n"
|
|
162
|
+
" pushq " SCR_STR(SCR_UC_GREG(REG_RIP)) "(%rdi)\n"
|
|
163
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RDI)) "(%rdi), %rdi\n"
|
|
164
|
+
" xorl %eax, %eax\n"
|
|
165
|
+
" ret\n"
|
|
166
|
+
|
|
167
|
+
".global swapcontext\n"
|
|
168
|
+
"swapcontext:\n"
|
|
169
|
+
" movq %r8, " SCR_STR(SCR_UC_GREG(REG_R8)) "(%rdi)\n"
|
|
170
|
+
" movq %r9, " SCR_STR(SCR_UC_GREG(REG_R9)) "(%rdi)\n"
|
|
171
|
+
" movq %r10, " SCR_STR(SCR_UC_GREG(REG_R10)) "(%rdi)\n"
|
|
172
|
+
" movq %r11, " SCR_STR(SCR_UC_GREG(REG_R11)) "(%rdi)\n"
|
|
173
|
+
" movq %r12, " SCR_STR(SCR_UC_GREG(REG_R12)) "(%rdi)\n"
|
|
174
|
+
" movq %r13, " SCR_STR(SCR_UC_GREG(REG_R13)) "(%rdi)\n"
|
|
175
|
+
" movq %r14, " SCR_STR(SCR_UC_GREG(REG_R14)) "(%rdi)\n"
|
|
176
|
+
" movq %r15, " SCR_STR(SCR_UC_GREG(REG_R15)) "(%rdi)\n"
|
|
177
|
+
" movq %rdi, " SCR_STR(SCR_UC_GREG(REG_RDI)) "(%rdi)\n"
|
|
178
|
+
" movq %rsi, " SCR_STR(SCR_UC_GREG(REG_RSI)) "(%rdi)\n"
|
|
179
|
+
" movq %rbp, " SCR_STR(SCR_UC_GREG(REG_RBP)) "(%rdi)\n"
|
|
180
|
+
" movq %rbx, " SCR_STR(SCR_UC_GREG(REG_RBX)) "(%rdi)\n"
|
|
181
|
+
" movq %rdx, " SCR_STR(SCR_UC_GREG(REG_RDX)) "(%rdi)\n"
|
|
182
|
+
" movq %rax, " SCR_STR(SCR_UC_GREG(REG_RAX)) "(%rdi)\n"
|
|
183
|
+
" movq %rcx, " SCR_STR(SCR_UC_GREG(REG_RCX)) "(%rdi)\n"
|
|
184
|
+
" movq (%rsp), %rcx\n"
|
|
185
|
+
" movq %rcx, " SCR_STR(SCR_UC_GREG(REG_RIP)) "(%rdi)\n"
|
|
186
|
+
" leaq 8(%rsp), %rcx\n"
|
|
187
|
+
" movq %rcx, " SCR_STR(SCR_UC_GREG(REG_RSP)) "(%rdi)\n"
|
|
188
|
+
" leaq 424(%rdi), %rcx\n"
|
|
189
|
+
" movq %rcx, 224(%rdi)\n"
|
|
190
|
+
" fnstenv (%rcx)\n"
|
|
191
|
+
" fldenv (%rcx)\n"
|
|
192
|
+
" stmxcsr 448(%rdi)\n"
|
|
193
|
+
" movq 224(%rsi), %rcx\n"
|
|
194
|
+
" fldenv (%rcx)\n"
|
|
195
|
+
" ldmxcsr 448(%rsi)\n"
|
|
196
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R8)) "(%rsi), %r8\n"
|
|
197
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R9)) "(%rsi), %r9\n"
|
|
198
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R10)) "(%rsi), %r10\n"
|
|
199
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R11)) "(%rsi), %r11\n"
|
|
200
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R12)) "(%rsi), %r12\n"
|
|
201
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R13)) "(%rsi), %r13\n"
|
|
202
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R14)) "(%rsi), %r14\n"
|
|
203
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_R15)) "(%rsi), %r15\n"
|
|
204
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RDI)) "(%rsi), %rdi\n"
|
|
205
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RBP)) "(%rsi), %rbp\n"
|
|
206
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RBX)) "(%rsi), %rbx\n"
|
|
207
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RDX)) "(%rsi), %rdx\n"
|
|
208
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RAX)) "(%rsi), %rax\n"
|
|
209
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RCX)) "(%rsi), %rcx\n"
|
|
210
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RSP)) "(%rsi), %rsp\n"
|
|
211
|
+
" pushq " SCR_STR(SCR_UC_GREG(REG_RIP)) "(%rsi)\n"
|
|
212
|
+
" movq " SCR_STR(SCR_UC_GREG(REG_RSI)) "(%rsi), %rsi\n"
|
|
213
|
+
" xorl %eax, %eax\n"
|
|
214
|
+
" ret\n"
|
|
215
|
+
|
|
216
|
+
".hidden scr_musl_context_trampoline\n"
|
|
217
|
+
"scr_musl_context_trampoline:\n"
|
|
218
|
+
" movq (%rbx), %rdi\n"
|
|
219
|
+
" testq %rdi, %rdi\n"
|
|
220
|
+
" je 1f\n"
|
|
221
|
+
" call setcontext\n"
|
|
222
|
+
" ud2\n"
|
|
223
|
+
"1:\n"
|
|
224
|
+
" xorl %edi, %edi\n"
|
|
225
|
+
" call exit\n"
|
|
226
|
+
" ud2\n");
|
|
227
|
+
|
|
228
|
+
extern void scr_musl_context_trampoline(void);
|
|
229
|
+
|
|
230
|
+
void makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) {
|
|
231
|
+
greg_t *sp;
|
|
232
|
+
va_list va;
|
|
233
|
+
int i;
|
|
234
|
+
unsigned int link_slot = (unsigned int)(argc > 6 ? argc - 6 : 0) + 1;
|
|
235
|
+
|
|
236
|
+
sp = (greg_t *)((uintptr_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
|
|
237
|
+
sp -= link_slot;
|
|
238
|
+
sp = (greg_t *)(((uintptr_t)sp & ~(uintptr_t)15) - 8);
|
|
239
|
+
|
|
240
|
+
ucp->uc_mcontext.fpregs = (void *)&ucp->__fpregs_mem;
|
|
241
|
+
ucp->uc_mcontext.gregs[REG_RIP] = (greg_t)(uintptr_t)func;
|
|
242
|
+
ucp->uc_mcontext.gregs[REG_RBX] = (greg_t)(uintptr_t)&sp[link_slot];
|
|
243
|
+
ucp->uc_mcontext.gregs[REG_RSP] = (greg_t)(uintptr_t)sp;
|
|
244
|
+
|
|
245
|
+
sp[0] = (greg_t)(uintptr_t)&scr_musl_context_trampoline;
|
|
246
|
+
sp[link_slot] = (greg_t)(uintptr_t)ucp->uc_link;
|
|
247
|
+
|
|
248
|
+
va_start(va, argc);
|
|
249
|
+
for (i = 0; i < argc; i++) {
|
|
250
|
+
greg_t arg = va_arg(va, greg_t);
|
|
251
|
+
switch (i) {
|
|
252
|
+
case 0: ucp->uc_mcontext.gregs[REG_RDI] = arg; break;
|
|
253
|
+
case 1: ucp->uc_mcontext.gregs[REG_RSI] = arg; break;
|
|
254
|
+
case 2: ucp->uc_mcontext.gregs[REG_RDX] = arg; break;
|
|
255
|
+
case 3: ucp->uc_mcontext.gregs[REG_RCX] = arg; break;
|
|
256
|
+
case 4: ucp->uc_mcontext.gregs[REG_R8] = arg; break;
|
|
257
|
+
case 5: ucp->uc_mcontext.gregs[REG_R9] = arg; break;
|
|
258
|
+
default: sp[i - 5] = arg; break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
va_end(va);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#undef SCR_UC_GREG
|
|
265
|
+
#undef SCR_STR
|
|
266
|
+
#undef SCR_STR_INNER
|
|
267
|
+
|
|
268
|
+
#endif /* !SCR_LIB */
|
|
269
|
+
|
|
270
|
+
#else /* !SCR_MUSL */
|
|
271
|
+
|
|
272
|
+
typedef int scr_musl_unused;
|
|
273
|
+
|
|
274
|
+
#endif /* SCR_MUSL */
|