Skip to content

Commit a3e3f17

Browse files
committedSep 1, 2022
Make the build work on GCC + Linux
1 parent 6a2dd45 commit a3e3f17

24 files changed

+507
-361
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/out
2+
/out-*
23
/deps
34
/work
45
/build.ninja

‎.logbook/2022-08-31.txt

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Put together a tool for keeping a logbook.
2+
Since I'm a very creative person I named it "logbook".
3+
4+
But really, today is about getting RSM building on Linux with GCC.
5+
It turns out there are a lot of things that GCC doesn't like but
6+
which clang is happy with. For example, a CPP macro that includes
7+
__has_builtin will cause GCC to cry a little so I'm unboxing HAS_LIBC_BUILTIN.
8+
9+
It's been a few hours now and it finally builds without any warnings in GCC 11.
10+
11+
Interestingly, GCC defines uint64_t as unsigned long on x86_64 and
12+
sizeof(long long) == sizeof(long). Clang does what I would expect and defines
13+
uint64_t as unsigned long long. Very odd. This GCC weirdness meant I had to change
14+
A TON of printf-like calls that use %ll for u64 values. Instead of the madness that
15+
is PRIu64, I ended up with typedef unsigned long long ull_t (and ill_t) which are
16+
used in typecasts for a u64 value when it is printed.
17+
18+
Thought: Maybe define i64 as long long instead.
19+
It would require some tricky stuff for the API header rsm.h which uses stdint
20+
uint64_t types. I.e. without changing all uint64_t types in rsm.h to something like
21+
rsm_u64_t, its ABI would be incorrect; i.e. on GCC the prototype would say "long"
22+
but the implementation would use "long long."
23+
24+
A nut to crack on another day.

‎build.sh

+58-14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ NINJA_ARGS=()
1313
NON_WATCH_ARGS=()
1414
TESTING_ENABLED=
1515
STRIP=false
16+
STATIC=false
1617
DEBUGGABLE=false
1718

1819
while [[ $# -gt 0 ]]; do
@@ -28,6 +29,8 @@ while [[ $# -gt 0 ]]; do
2829
-fast) BUILD_MODE=fast; TESTING_ENABLED=; shift ;;
2930
-debug) BUILD_MODE=debug; TESTING_ENABLED=1; DEBUGGABLE=true; shift ;;
3031
-strip) STRIP=true; DEBUGGABLE=false; shift ;;
32+
-static) STATIC=true; shift ;;
33+
-out=*) OUTDIR=${1:5}; shift; continue ;;
3134
-g) DEBUGGABLE=true; shift ;;
3235
-v) NINJA_ARGS+=(-v); shift ;;
3336
-h|-help|--help) cat << _END
@@ -41,6 +44,7 @@ options:
4144
-w Rebuild as sources change
4245
-wf=<file> Watch <file> for changes (can be provided multiple times)
4346
-run=<cmd> Run <cmd> after successful build
47+
-out=<dir> Build in <dir> instead of "$OUTDIR".
4448
-help Show help on stdout and exit
4549
_END
4650
exit ;;
@@ -52,7 +56,22 @@ esac; done
5256

5357
# -w to enter "watch & build & run" mode
5458
if [ -n "$WATCH" ]; then
55-
command -v fswatch >/dev/null || _err "fswatch not found in PATH"
59+
WATCH_TOOL=fswatch
60+
# note: inotifywait is part of inotify-tools
61+
command -v $WATCH_TOOL >/dev/null || WATCH_TOOL=inotifywait
62+
command -v $WATCH_TOOL >/dev/null ||
63+
_err "no watch tool available (looked for fswatch and inotifywait in PATH)"
64+
65+
_fswatch() {
66+
if [ "$WATCH_TOOL" = fswatch ]; then
67+
fswatch --one-event --extended --latency=0.1 \
68+
--exclude='\.(a|o)$' --recursive "$@"
69+
else
70+
inotifywait -e modify -e create -e delete -e move -qq \
71+
--exclude='\.(a|o)$' --recursive "$@"
72+
fi
73+
}
74+
5675
# case "$RUN" in
5776
# *" "*) RUN="$SHELL -c '$RUN'" ;;
5877
# esac
@@ -94,15 +113,13 @@ if [ -n "$WATCH" ]; then
94113
echo "$RUN (#$RUN_PID) exited"
95114
) &
96115
fi
97-
fswatch --one-event --extended --latency=0.1 \
98-
--exclude='\.(a|o)$' \
99-
--recursive \
100-
src "$(basename "$0")" "${WATCH_ADDL_FILES[@]}"
116+
_fswatch src "$(basename "$0")" "${WATCH_ADDL_FILES[@]}"
101117
done
102118
exit 0
103119
fi
104120

105121
CC_IS_CLANG=false
122+
CC_IS_GCC=false
106123
if [ -z "$CC" ]; then
107124
# use clang from known preferred location, if available
108125
if [ -x /usr/local/opt/llvm/bin/clang ]; then
@@ -113,14 +130,20 @@ if [ -z "$CC" ]; then
113130
export PATH=/opt/homebrew/opt/llvm/bin:$PATH
114131
export CC=clang
115132
CC_IS_CLANG=true
133+
elif command -v gcc > /dev/null; then
134+
export CC=gcc
135+
CC_IS_GCC=true
116136
else
117137
export CC=cc
118138
fi
119139
fi
120140
CC_PATH=$(command -v "$CC" || true)
121-
[ -f "$CC_PATH" ] || _err "CC (\"$CC\") not found"
122-
if ! $CC_IS_CLANG && $CC --version 2>/dev/null | head -n1 | grep -q clang; then
123-
CC_IS_CLANG=true
141+
[ -f "$CC_PATH" ] || _err "no suitable compiler found (CC=\"$CC\")"
142+
if ! $CC_IS_CLANG && ! $CC_IS_GCC; then
143+
case "$($CC --version 2>/dev/null)" in
144+
*clang*) CC_IS_CLANG=true ;;
145+
*"Free Software Foundation"*) CC_IS_GCC=true ;;
146+
esac
124147
fi
125148
[ -z "$_WATCHED" ] && echo "using compiler $CC_PATH"
126149

@@ -148,7 +171,7 @@ LDFLAGS_HOST=( $LDFLAGS ) # LDFLAGS from env
148171
LDFLAGS_WASM=( $LDFLAGS_WASM ) # LDFLAGS_WASM from env (note: liker is wasm-ld, not cc)
149172

150173
if $DEBUG; then
151-
CFLAGS+=( -O0 -DDEBUG -ferror-limit=6 )
174+
CFLAGS+=( -O0 -DDEBUG )
152175
else
153176
CFLAGS+=( -DNDEBUG )
154177
# LDFLAGS_WASM+=( -z stack-size=$[128 * 1024] ) # larger stack, smaller heap
@@ -170,11 +193,36 @@ elif $DEBUGGABLE; then
170193
CFLAGS+=( -g -feliminate-unused-debug-types )
171194
fi
172195

196+
if $STATIC; then
197+
LDFLAGS_HOST+=( -static )
198+
fi
199+
200+
if $CC_IS_CLANG; then
201+
CFLAGS+=(
202+
-fcolor-diagnostics \
203+
-Wcovered-switch-default \
204+
-Werror=implicit-function-declaration \
205+
-Werror=incompatible-pointer-types \
206+
-Werror=format-insufficient-args \
207+
)
208+
elif $CC_IS_GCC; then
209+
CFLAGS+=(
210+
-fdiagnostics-color \
211+
-Wswitch-enum \
212+
-Wno-format-zero-length \
213+
-Wno-comment \
214+
-Wno-expansion-to-defined \
215+
-Wno-type-limits \
216+
)
217+
fi
218+
173219
# enable llvm address and UD sanitizer in debug builds
174220
if $DEBUG && $CC_IS_CLANG; then
175221
# See https://clang.llvm.org/docs/AddressSanitizer.html
176222
# See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
177223
CFLAGS_HOST+=(
224+
-ferror-limit=6 \
225+
\
178226
-fsanitize=address,undefined \
179227
\
180228
-fsanitize-address-use-after-scope \
@@ -201,16 +249,12 @@ objdir = \$builddir/$BUILD_MODE
201249
202250
cflags = $
203251
-std=c11 $
204-
-fcolor-diagnostics $
205252
-fvisibility=hidden $
206253
-Wall -Wextra -Wvla $
207254
-Wimplicit-fallthrough $
208255
-Wno-missing-field-initializers $
209256
-Wno-unused-parameter $
210-
-Werror=implicit-function-declaration $
211-
-Werror=incompatible-pointer-types $
212-
-Werror=format-insufficient-args $
213-
-Wcovered-switch-default ${CFLAGS[@]}
257+
${CFLAGS[@]}
214258
215259
cflags_host = ${CFLAGS_HOST[@]}
216260

‎src/array.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void _rarray_remove(rarray* a, u32 elemsize, u32 start, u32 len) {
1616
}
1717

1818
bool rarray_grow(rarray* a, rmemalloc_t* ma, u32 elemsize, u32 addl) {
19-
u32 newcap = a->cap ? (u32)MIN((u64)a->cap * 2, U32_MAX) : MAX(addl, 4);
19+
u32 newcap = a->cap ? (u32)MIN((u64)a->cap * 2, U32_MAX) : MAX(addl, 4u);
2020
usize newsize;
2121
if (check_mul_overflow((usize)newcap, (usize)elemsize, &newsize))
2222
return false;

‎src/asm.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ static void* nullable bufslab_alloc_more(bufslabs* slabs, rmemalloc_t* ma, u32 l
321321
goto finalize;
322322
}
323323
// no free space found -- allocate new slab
324-
u32 cap = MAX(BUFSLAB_MIN_CAP, ALIGN2(len, 16));
324+
u32 cap = MAX(BUFSLAB_MIN_CAP, ALIGN2(len, 16u));
325325
rmem_t m = rmem_alloc_aligned(ma, sizeof(bufslab) + cap, _Alignof(bufslab));
326326
if UNLIKELY(!m.p)
327327
return NULL;

‎src/asm.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ typedef struct rposrange {
1515

1616
// rasm._internal[0] -- negated diaghandler return value
1717
#define rasm_stop(a) ( (bool)(a)->_internal[0] )
18-
#define rasm_stop_set(a,v) ( *(bool*)&(a)->_internal[0] = (v) )
18+
#define rasm_stop_set(a,v) ( (a)->_internal[0] = (uintptr)(v) )
1919

2020
// rasm._internal[1]-- reusable internal codegen state
2121
#define rasm_gstate(a) ( (gstate*)(a)->_internal[1] )
22-
#define rasm_gstate_set(a,v) ( *(gstate**)&(a)->_internal[1] = (v) )
22+
#define rasm_gstate_set(a,v) ( (a)->_internal[1] = (uintptr)(v) )
2323

2424
// rasm._internal[2]-- reusable internal codegen state
2525
#define rasm_pstate(a) ( (pstate*)(a)->_internal[2] )
26-
#define rasm_pstate_set(a,v) ( *(pstate**)&(a)->_internal[2] = (v) )
26+
#define rasm_pstate_set(a,v) ( (a)->_internal[2] = (uintptr)(v) )
2727

2828
const char* tokname(rtok_t t);
2929

@@ -76,8 +76,8 @@ static void dlog_asm(rmemalloc_t* ma, const rin_t* iv, usize icount);
7676
// ————————————————
7777
// bufslab
7878

79-
#define BUFSLAB_MIN_CAP 512
80-
#define BUFSLAB_ALIGN 16
79+
#define BUFSLAB_MIN_CAP 512u
80+
#define BUFSLAB_ALIGN 16u
8181
static_assert(BUFSLAB_MIN_CAP >= BUFSLAB_ALIGN, "");
8282
static_assert(IS_ALIGN2(BUFSLAB_MIN_CAP, BUFSLAB_ALIGN), "");
8383

‎src/asmgen.c

+15-14
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ static bool patch_imm(gstate* g, rnode_t* patcher, u32 inindex, u64 value, i32*
414414
largeval:
415415
// Does not fit in immediate value for the instruction.
416416
// Synthesize instructions to compute the value in a register.
417-
trace("op %s; large value 0x%llx", rop_name(RSM_GET_OP(*in)), value);
417+
trace("op %s; large value 0x%llx", rop_name(RSM_GET_OP(*in)), (ull_t)value);
418418

419419
if (scratchreg >= RSM_NREGS) {
420420
// >RSM_NREGS: no scratch register; instruction does not produce a register result.
@@ -551,7 +551,7 @@ static void resolve_undefined_names(gstate* g) {
551551
d->nrefs++;
552552

553553
dlog_datalayout("patching data reference %.*s (gdata %p, addr 0x%llx)",
554-
(int)namelen, name, d, d->addr);
554+
(int)namelen, name, d, (ull_t)d->addr);
555555

556556
i32 ignore;
557557
patch_imm(g, ref->n, ref->i, d->addr, &ignore);
@@ -626,7 +626,7 @@ static bool refnamed(gstate* g, rnode_t* refn, u32 refi, u32 argc, i32* argp) {
626626

627627
// get the constant's value (e.g. 0xBEEF for "const x = 0xBEEF").
628628
u64 value = *(const u64*)assertnotnull( ((gdata*)target)->initp );
629-
trace("constant value: 0x%llx", value);
629+
trace("constant value: 0x%llx", (ull_t)value);
630630

631631
// patch_imm sets last argument of the rin_t at g->iv[refi] to value
632632
return patch_imm(g, refn, refi, value, argp);
@@ -653,13 +653,14 @@ static u8 nregno(gstate* g, rnode_t* n) {
653653
}
654654

655655
static void errintsize(
656-
rasm_t* c, rposrange_t pr, rop_t op, i64 minval, i64 maxval, u64 val, bool issigned)
656+
rasm_t* c, rposrange_t pr, rop_t op, i64 minval, u64 maxval, u64 val, bool issigned)
657657
{
658658
if (minval != 0 || issigned) {
659-
errf(c, pr, "value %lld out of range %lld...%lld for %s",
660-
(i64)val, minval, maxval, rop_name(op));
659+
errf(c, pr, "value %lld out of range %lld...%llu for %s",
660+
(ill_t)val, (ill_t)minval, (ull_t)maxval, rop_name(op));
661661
} else {
662-
errf(c, pr, "value %llu out of range 0...%lld for %s", val, maxval, rop_name(op));
662+
errf(c, pr, "value %llu out of range 0...%llu for %s",
663+
(ull_t)val, (ull_t)maxval, rop_name(op));
663664
}
664665
}
665666

@@ -679,7 +680,7 @@ static bool getiargs(
679680
rop_t op = (rop_t)n->ival;
680681

681682
trace("[%s] wantargc %u, minval %lld, maxval 0x%llx",
682-
rop_name(op), wantargc, minval, maxval);
683+
rop_name(op), wantargc, (ill_t)minval, (ull_t)maxval);
683684

684685
// first argc-1 args are registers
685686
rnode_t* arg = n->children.head;
@@ -890,17 +891,17 @@ static void genop(gstate* g, rnode_t* n) {
890891
return;
891892
make_A: NOIMM(1, A , arg[0])
892893
make_Au: RoIMM(1, A, Au , 0, RSM_MAX_Au, arg[0])
893-
make_As: RoIMM(1, A, As , RSM_MIN_As, RSM_MAX_As, arg[0])
894-
make_AB: NOIMM(2, AB , arg[0], arg[1])
894+
//make_As: RoIMM(1, A, As , RSM_MIN_As, RSM_MAX_As, arg[0])
895+
//make_AB: NOIMM(2, AB , arg[0], arg[1])
895896
make_ABv: RvIMM(2, ABv , 0, U64_MAX, arg[0], arg[1])
896897
make_ABu: RoIMM(2, AB, ABu , 0, RSM_MAX_Bu, arg[0], arg[1])
897898
make_ABs: RoIMM(2, AB, ABs , RSM_MIN_Bs, RSM_MAX_Bs, arg[0], arg[1])
898-
make_ABC: NOIMM(3, ABC , arg[0], arg[1], arg[2])
899+
//make_ABC: NOIMM(3, ABC , arg[0], arg[1], arg[2])
899900
make_ABCu: RoIMM(3, ABC, ABCu , 0, RSM_MAX_Cu, arg[0], arg[1], arg[2])
900901
make_ABCs: RoIMM(3, ABC, ABCs , RSM_MIN_Cs, RSM_MAX_Cs, arg[0], arg[1], arg[2])
901-
make_ABCD: NOIMM(4, ABCD , arg[0], arg[1], arg[2], arg[3])
902+
//make_ABCD: NOIMM(4, ABCD , arg[0], arg[1], arg[2], arg[3])
902903
make_ABCDu: RoIMM(4, ABCD, ABCDu, 0, RSM_MAX_Du, arg[0], arg[1], arg[2], arg[3])
903-
make_ABCDs: RoIMM(4, ABCD, ABCDs, RSM_MIN_Ds, RSM_MAX_Ds, arg[0], arg[1], arg[2], arg[3])
904+
//make_ABCDs: RoIMM(4, ABCD, ABCDs, RSM_MIN_Ds, RSM_MAX_Ds, arg[0], arg[1], arg[2], arg[3])
904905
DIAGNOSTIC_IGNORE_POP()
905906
#undef RoIMM
906907
#undef NOIMM
@@ -1175,7 +1176,7 @@ static void dlog_gdata(gdata* nullable d) {
11751176
if (namelen > namemax) { namemax--; namelen = namemax; nametail = "…"; }
11761177
if (datalen > datamax) { datamax--; datalen = datamax; datatail = "…"; }
11771178
log("0x%016llx %-*.*s%s %10zu %2u %.*s%s",
1178-
d->addr,
1179+
(ull_t)d->addr,
11791180
namemax, namelen, d->name, nametail,
11801181
d->size, d->align,
11811182
datalen, reprbuf, datatail);

‎src/asmparse.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,7 @@ static rnode_t* parraytype(PPARAMS, rnode_t* elemtype) {
952952
if (!tokisintlit(p->tok)) {
953953
perrunexpected(p, NULL, "size constant as integer literal", tokname(p->tok));
954954
} else if (p->ival == 0 || (tokissint(p->tok) && (i64)p->ival < 0)) {
955-
perr(p, NULL, "invalid array size %lld", (i64)p->ival);
955+
perr(p, NULL, "invalid array size %lld", (ull_t)p->ival);
956956
}
957957
n->ival = p->ival;
958958
sadvance(p);

‎src/exec_v1.c

+21-20
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ static_assert(offsetof(vmstate,pub) == 0, "vmstate.pub is not first member");
4949
}
5050
static void logstate(VMPARAMS) {
5151
for (int i = 0; i < 6; i++)
52-
fprintf(stderr, REG_FMTVAL_PAT("%5llx"), REG_FMTVAL(i, iregs[i]));
52+
fprintf(stderr, REG_FMTVAL_PAT("%5llx"), REG_FMTVAL(i, (ull_t)iregs[i]));
5353
char buf[128];
5454
rsm_fmtinstr(buf, sizeof(buf), inv[pc], NULL, RSM_FMT_COLOR);
5555
fprintf(stderr, REG_FMTVAL_PAT("%6llx") " │ %3ld %s\n",
56-
REG_FMTVAL(RSM_MAX_REG, iregs[RSM_MAX_REG]), pc, buf);
56+
REG_FMTVAL(RSM_MAX_REG, (ull_t)iregs[RSM_MAX_REG]), pc, buf);
5757
}
5858
#ifdef DEBUG_VM_LOG_LOADSTORE
5959
#define log_loadstore dlog
@@ -68,10 +68,10 @@ static_assert(offsetof(vmstate,pub) == 0, "vmstate.pub is not first member");
6868

6969

7070
// constants
71-
#define STK_ALIGN 8 // stack alignment (== sizeof(u64))
72-
#define STK_MIN 2048 // minium stack size (TODO: consider making part of ROM)
73-
#define STK_MAX (1024*1024) // maximum stack size
74-
#define MAIN_RET_PC USIZE_MAX // special PC value representing the main return address
71+
#define STK_ALIGN 8u // stack alignment (== sizeof(u64))
72+
#define STK_MIN 2048u // minium stack size (TODO: consider making part of ROM)
73+
#define STK_MAX (1u*MiB) // maximum stack size
74+
#define MAIN_RET_PC USIZE_MAX // special PC value representing the main return address
7575

7676
static_assert(STK_MIN % STK_ALIGN == 0, "STK_MIN not aligned to STK_ALIGN");
7777

@@ -123,17 +123,18 @@ static void _vmerr(VMPARAMS, vmerror err, u64 arg1, u64 arg2) {
123123
char buf[2048];
124124
abuf_t s1 = abuf_make(buf, sizeof(buf)); abuf_t* s = &s1;
125125
pc--; // undo the increment to make pc point to the violating instruction
126+
ull_t a1 = (ull_t)arg1, a2 = (ull_t)arg2;
126127
#define S(ERR, fmt, args...) case ERR: abuf_fmt(s, fmt, ##args); break;
127128
switch ((enum vmerror)err) {
128-
S(VM_E_UNALIGNED_STORE, "unaligned memory store %llx (align %llu B)", arg1, arg2)
129-
S(VM_E_UNALIGNED_ACCESS,"unaligned memory access %llx (align %llu B)", arg1, arg2)
130-
S(VM_E_UNALIGNED_STACK, "unaligned stack pointer SP=%llx (align %d B)", arg1, STK_ALIGN)
131-
S(VM_E_STACK_OVERFLOW, "stack overflow %llx (align %llu B)", arg1, arg2)
132-
S(VM_E_OOB_LOAD, "memory load out of bounds %llx (align %llu B)", arg1, arg2)
133-
S(VM_E_OOB_STORE, "memory store out of bounds %llx (align %llu B)", arg1, arg2)
134-
S(VM_E_OOB_PC, "PC out of bounds %llx", arg1)
135-
S(VM_E_OPNOI, "op %s does not accept immediate value", rop_name(arg1))
136-
S(VM_E_SHIFT_EXP, "shift exponent %llu is too large", arg1)
129+
S(VM_E_UNALIGNED_STORE, "unaligned memory store %llx (align %llu B)", a1, a2)
130+
S(VM_E_UNALIGNED_ACCESS,"unaligned memory access %llx (align %llu B)", a1, a2)
131+
S(VM_E_UNALIGNED_STACK, "unaligned stack pointer SP=%llx (align %d B)", a1, STK_ALIGN)
132+
S(VM_E_STACK_OVERFLOW, "stack overflow %llx (align %llu B)", a1, a2)
133+
S(VM_E_OOB_LOAD, "memory load out of bounds %llx (align %llu B)", a1, a2)
134+
S(VM_E_OOB_STORE, "memory store out of bounds %llx (align %llu B)", a1, a2)
135+
S(VM_E_OOB_PC, "PC out of bounds %llx", a1)
136+
S(VM_E_OPNOI, "op %s does not accept immediate value", rop_name(a1))
137+
S(VM_E_SHIFT_EXP, "shift exponent %llu is too large", a1)
137138
}
138139
#undef S
139140
abuf_c(s, '\n');
@@ -150,11 +151,11 @@ static void _vmerr(VMPARAMS, vmerror err, u64 arg1, u64 arg2) {
150151
abuf_fmt(s, "\n R%u…%u", i, MIN(i+7, endi-1));
151152
abuf_fill(s, ' ', 10 - (s->len - len - 1));
152153
}
153-
abuf_fmt(s, " %8llx", iregs[i]);
154+
abuf_fmt(s, " %8llx", (ull_t)iregs[i]);
154155
}
155156
usize stacktop = ALIGN2(vs->datasize, STK_ALIGN);
156157
usize stacksize = vs->stackbase - stacktop;
157-
abuf_fmt(s, "\n SP %8llx", SP);
158+
abuf_fmt(s, "\n SP %8llx", (ull_t)SP);
158159

159160
usize heapsize = vs->msize[0] - vs->heapbase;
160161
abuf_fmt(s, "\nMemory: (%lu B)", vs->msize[0]);
@@ -218,21 +219,21 @@ inline static void* hostaddr_check_access(VMPARAMS, u64 align, u64 addr) {
218219
// inline u64 LOAD(TYPE, u64 addr)
219220
#define LOAD(TYPE, addr) ({ u64 a__=(addr); \
220221
u64 v__ = *(TYPE*)hostaddr_check_access(VMARGS, sizeof(TYPE), a__); \
221-
log_loadstore("LOAD %s mem[0x%llx] => 0x%llx", #TYPE, a__, v__); \
222+
log_loadstore("LOAD %s mem[0x%llx] => 0x%llx", #TYPE, (ull_t)a__, (ull_t)v__); \
222223
v__; \
223224
})
224225

225226
// inline void STORE(TYPE, u64 addr, u64 value)
226227
#define STORE(TYPE, addr, value) { u64 a__=(addr), v__=(value); \
227-
log_loadstore("STORE %s mem[0x%llx] <= 0x%llx", #TYPE, a__, v__); \
228+
log_loadstore("STORE %s mem[0x%llx] <= 0x%llx", #TYPE, (ull_t)a__, (ull_t)v__); \
228229
check_loadstore(a__, sizeof(TYPE), VM_E_UNALIGNED_STORE, VM_E_OOB_STORE); \
229230
usize index = mbase_index(VMARGS, a__); \
230231
*(TYPE*)(vs->mbase[index] + a__ - index*M_SEG_SIZE) = v__; \
231232
}
232233

233234
// inline void STORE_RAM(TYPE, u64 addr, u64 value)
234235
#define STORE_RAM(TYPE, addr, value) { u64 a__=(addr), v__=(value); \
235-
log_loadstore("STORE %s mem[0x%llx] <= 0x%llx", #TYPE, a__, v__); \
236+
log_loadstore("STORE %s mem[0x%llx] <= 0x%llx", #TYPE, (ull_t)a__, (ull_t)v__); \
236237
assert(a__ < M_SEG_SIZE); \
237238
check_loadstore(a__, sizeof(TYPE), VM_E_UNALIGNED_STORE, VM_E_OOB_STORE); \
238239
*(u64*)(vs->mbase[0] + (uintptr)a__) = v__; \

‎src/hash.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ void fastrand_seed(u64 seed) {
1616
fastrand_state = seed;
1717
}
1818

19+
typedef u64 ATTR_MAY_ALIAS u64a_t;
20+
1921
u32 fastrand() {
2022
#ifdef __SIZEOF_INT128__
2123
// wyrand (https://github.com/wangyi-fudan/wyhash)
@@ -24,9 +26,9 @@ u32 fastrand() {
2426
__uint128_t r =
2527
(__uint128_t)fastrand_state * (__uint128_t)(fastrand_state ^ 0xe7037ed1a0b428db);
2628
#if RSM_LITTLE_ENDIAN
27-
u64 hi = ((u64*)&r)[0], lo = ((u64*)&r)[1];
29+
u64a_t hi = ((u64a_t*)&r)[0], lo = ((u64a_t*)&r)[1];
2830
#else
29-
u64 hi = ((u64*)&r)[1], lo = ((u64*)&r)[0];
31+
u64a_t hi = ((u64a_t*)&r)[1], lo = ((u64a_t*)&r)[0];
3032
#endif
3133
return (u32)(hi ^ lo);
3234
#else

‎src/lz4.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434

3535
// RSM addition: silence -Wcovered-switch-default
3636
// "default label in switch which covers all enumeration values"
37-
#if defined(__clang__) || defined(__gcc__)
38-
_Pragma("GCC diagnostic ignored \"-Wcovered-switch-default\"")
37+
#if defined(__clang__) && defined(_Pragma)
38+
_Pragma("GCC diagnostic ignored \"-Wcovered-switch-default\"")
3939
#endif
4040

4141
/*-************************************

‎src/main.c

+12-12
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ static int setreg(u64* iregs, const char* s) {
3636
if (parseu64(s, p-1, 10, &regno, 0xff) != 0)
3737
goto malformed;
3838
if (regno > RSM_MAX_REG) {
39-
errmsg("invalid register -R%llu", regno);
39+
errmsg("invalid register -R%llu", (ull_t)regno);
4040
return 1;
4141
}
4242
if (parseu64(vals, vallen, base, &iregs[regno], 0xffffffffffffffff) == 0)
@@ -211,28 +211,28 @@ static void print_regstate_x64(bool pad, u64 v) {
211211
v > 0xfff ? 4 : v > 0xff ? 3 :
212212
v > 0xf ? 2 : 1
213213
);
214-
printf(pad ? " %*s0x%llx" : "%*s0x%llx", 18 - w, "", v);
214+
printf(pad ? " %*s0x%llx" : "%*s0x%llx", 18 - w, "", (ull_t)v);
215215
}
216216

217217
static void print_regstate(u64* iregs) {
218218
printf("register state:\n");
219219
for(u32 i=0;i<4;i++)
220220
printf(i==3 ? " R%u" : i ? " R%-19u" : " R%-19u", i);
221221
printf("\nU64 "); for (u32 i=0;i<4;i++) print_regstate_x64(i, iregs[i]);
222-
printf("\nU64 "); for(u32 i=0;i<4;i++) printf(i ? " %20llu" : "%20llu", iregs[i]);
223-
printf("\nS64 "); for(u32 i=0;i<4;i++) printf(i ? " %20lld" : "%20lld", (i64)iregs[i]);
224-
printf("\nS32 "); for(u32 i=0;i<4;i++) printf(i ? " %20d" : "%20d", (i32)iregs[i]);
225-
printf("\nS16 "); for(u32 i=0;i<4;i++) printf(i ? " %20d" : "%20d", (i16)iregs[i]);
226-
printf("\nS8 "); for(u32 i=0;i<4;i++) printf(i ? " %20d" : "%20d", (i8)iregs[i]);
222+
printf("\nU64 "); for(u32 i=0;i<4;i++) printf(i ? " %20llu" : "%20llu",(ull_t)iregs[i]);
223+
printf("\nS64 "); for(u32 i=0;i<4;i++) printf(i ? " %20lld" : "%20lld",(ill_t)iregs[i]);
224+
printf("\nS32 "); for(u32 i=0;i<4;i++) printf(i ? " %20d" : "%20d", (i32)iregs[i]);
225+
printf("\nS16 "); for(u32 i=0;i<4;i++) printf(i ? " %20d" : "%20d", (i16)iregs[i]);
226+
printf("\nS8 "); for(u32 i=0;i<4;i++) printf(i ? " %20d" : "%20d", (i8)iregs[i]);
227227
printf("\n\n");
228228
for(u32 i=4;i<8;i++)
229229
printf(i==7 ? " R%u" : i>4 ? " R%-19u" : " R%-19u", i);
230230
printf("\nU64 "); for(u32 i=4;i<8;i++) print_regstate_x64(i>4, iregs[i]);
231-
printf("\nU64 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20llu" : "%20llu", iregs[i]);
232-
printf("\nS64 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20lld" : "%20lld", (i64)iregs[i]);
233-
printf("\nS32 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20d" : "%20d", (i32)iregs[i]);
234-
printf("\nS16 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20d" : "%20d", (i16)iregs[i]);
235-
printf("\nS8 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20d" : "%20d", (i8)iregs[i]);
231+
printf("\nU64 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20llu" : "%20llu",(ull_t)iregs[i]);
232+
printf("\nS64 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20lld" : "%20lld",(ill_t)iregs[i]);
233+
printf("\nS32 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20d" : "%20d", (i32)iregs[i]);
234+
printf("\nS16 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20d" : "%20d", (i16)iregs[i]);
235+
printf("\nS8 "); for(u32 i=4;i<8;i++) printf(i>4 ? " %20d" : "%20d", (i8)iregs[i]);
236236
printf("\n");
237237
}
238238

‎src/map.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ usize smap_cfmt(char* buf, usize bufcap, const smap* m, const char* name) {
382382
"static const struct{u32 cap,len,gcap;maplf lf;hash_t hash0;const smapent* ep;}\n"
383383
"%s_data={%u,%u,%u,%u,0x%llx,%s_entries};\n"
384384
"static const smap* %s = (const smap*)&%s_data;",
385-
name, m->cap, m->len, m->gcap, m->lf, (u64)m->hash0, name, name, name
385+
name, m->cap, m->len, m->gcap, m->lf, (ull_t)m->hash0, name, name, name
386386
);
387387
return abuf_terminate(&s);
388388
}

‎src/qsort.c

+2-11
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,10 @@
2727
// void* ctx, ← ctx position
2828
// int (*cmp)(void* ctx, const void* x, const void* y)); ← cmp & ctx position
2929
//
30-
// For this reason we use qsort from musl (unless we are linking with a compatible libc)
30+
// For this reason we use qsort from musl
3131
//
3232
#include "rsmimpl.h"
33-
#if !defined(RSM_NO_LIBC) && defined(__linux__)
34-
#include <stdlib.h>
35-
void rsm_qsort(void* base, usize nmemb, usize size, rsm_qsort_cmp cmp, void* nullable ctx) {
36-
return qsort_r(base, nmemb, size, cmp, ctx);
37-
}
38-
#else
39-
// use qsort from musl, licensed as follows:
33+
// qsort from musl, licensed as follows:
4034

4135
/* Copyright (C) 2011 by Valentin Ochs
4236
*
@@ -255,6 +249,3 @@ void rsm_qsort(void *base, size_t nel, size_t width, cmpfun cmp, void* nullable
255249
head -= width;
256250
}
257251
}
258-
259-
260-
#endif // RSM_NO_LIBC

‎src/rom.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
// ROM version range this code can handle.
77
// rom_build produces version ROM_VERSION_MAX ROMs.
8-
#define ROM_VERSION_MIN 0
9-
#define ROM_VERSION_MAX 0
8+
#define ROM_VERSION_MIN 0u
9+
#define ROM_VERSION_MAX 0u
1010

1111
// RSM_WITH_LZ4: define to enable creation of LZ4 compressed ROMs
1212
#define RSM_WITH_LZ4
@@ -146,7 +146,7 @@ usize rromimg_loadsize(const rromimg_t* img, usize imgsize) {
146146

147147
int z = LZ4_decompress_safe(src, dstmem.p, (int)compressed_size, (int)dstmem.size);
148148
if UNLIKELY(z < 0 || (u64)z != uncompressed_size) {
149-
dlog("LZ4_decompress_safe => %d (expected %llu)", z, uncompressed_size);
149+
dlog("LZ4_decompress_safe => %d (expected %llu)", z, (ull_t)uncompressed_size);
150150
log("%scorrupt compressed image", errprefix);
151151
return rerr_invalid;
152152
}
@@ -196,7 +196,7 @@ static rerr_t load_section_DATA(LPARAMS) {
196196
static rerr_t load_section_CODE(LPARAMS) {
197197
ALIGN_P_AND_CHECK_BOUNDS(CODE_ALIGNMENT);
198198
if UNLIKELY(!IS_ALIGN2(size, CODE_ALIGNMENT))
199-
return perr("CODE section size %llu not aligned to %zu", size, CODE_ALIGNMENT);
199+
return perr("CODE section size %llu not aligned to %zu", (ull_t)size,CODE_ALIGNMENT);
200200
rom->code = (const void*)p;
201201
rom->codelen = (usize)( size / CODE_ALIGNMENT ); // #bytes -> #instructions
202202
p += size;

‎src/rsm.h

+72-65
Large diffs are not rendered by default.

‎src/rsmimpl.c

+84-79
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@
88
#include <errno.h>
99
#include <unistd.h>
1010
#include <stdlib.h> // free
11-
#include <execinfo.h> // backtrace* (for _panic)
1211
#include <sys/stat.h>
1312
#include <sys/mman.h> // mmap
1413
#include <string.h> // strerror
1514

15+
// backtrace* (for _panic) is not a libc standard
16+
// macOS has it, glibc has it (but we can't check at compile time)
17+
#if (defined(__MACH__) && defined(__APPLE__))
18+
#define RSM_HAS_BACKTRACE
19+
#include <execinfo.h>
20+
#endif
21+
1622
#ifdef _WIN32
1723
#define WIN32_LEAN_AND_MEAN
1824
#include <windows.h>
@@ -354,10 +360,10 @@ static char* strrevn(char* s, usize len) {
354360
return s;
355361
}
356362

357-
usize stru64(char buf[64], u64 v, u32 base) {
363+
usize stru64(char* buf, u64 v, u32 base) {
358364
static const char* chars =
359365
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
360-
base = MAX(2, MIN(base, 62));
366+
base = MIN(MAX(base, 2u), 62u);
361367
char* p = buf;
362368
do {
363369
*p++ = chars[v % base];
@@ -451,21 +457,25 @@ noreturn void _panic(const char* file, int line, const char* fun, const char* fm
451457
vfprintf(fp, fmt, ap);
452458
va_end(ap);
453459
fprintf(fp, " in %s at %s:%d\n", fun, file, line);
454-
void* buf[32];
455-
int framecount = backtrace(buf, countof(buf));
456-
if (framecount > 1) {
457-
char** strs = backtrace_symbols(buf, framecount);
458-
if (strs != NULL) {
459-
for (int i = 1; i < framecount; ++i) {
460-
fwrite(strs[i], strlen(strs[i]), 1, fp);
461-
fputc('\n', fp);
460+
461+
#ifdef RSM_HAS_BACKTRACE
462+
void* buf[32];
463+
int framecount = backtrace(buf, countof(buf));
464+
if (framecount > 1) {
465+
char** strs = backtrace_symbols(buf, framecount);
466+
if (strs != NULL) {
467+
for (int i = 1; i < framecount; ++i) {
468+
fwrite(strs[i], strlen(strs[i]), 1, fp);
469+
fputc('\n', fp);
470+
}
471+
free(strs);
472+
} else {
473+
fflush(fp);
474+
backtrace_symbols_fd(buf, framecount, fileno(fp));
462475
}
463-
free(strs);
464-
} else {
465-
fflush(fp);
466-
backtrace_symbols_fd(buf, framecount, fileno(fp));
467476
}
468-
}
477+
#endif
478+
469479
funlockfile(fp);
470480
fflush(fp);
471481
fsync(STDERR_FILENO);
@@ -493,7 +503,7 @@ void* nullable osvmem_alloc(usize nbytes) {
493503

494504
void* ptr = mmap(0, nbytes, protection, flags, -1, 0);
495505

496-
if UNLIKELY(ptr == MAP_FAILED | ptr == NULL) {
506+
if UNLIKELY((ptr == MAP_FAILED) | (ptr == NULL)) {
497507
dlog("mmap failed with errno %d %s", errno, strerror(errno));
498508
return NULL;
499509
}
@@ -512,30 +522,29 @@ bool osvmem_free(void* ptr, usize nbytes) {
512522
}
513523

514524

525+
#if RSM_NO_CC_BUILTINS
526+
/* --- BEGIN musl code, licensed as followed (MIT) ---
527+
Copyright © 2005-2020 Rich Felker, et al.
515528
516-
/* --- BEGIN musl code, licensed as followed (MIT) ---
517-
Copyright © 2005-2020 Rich Felker, et al.
529+
Permission is hereby granted, free of charge, to any person obtaining
530+
a copy of this software and associated documentation files (the
531+
"Software"), to deal in the Software without restriction, including
532+
without limitation the rights to use, copy, modify, merge, publish,
533+
distribute, sublicense, and/or sell copies of the Software, and to
534+
permit persons to whom the Software is furnished to do so, subject to
535+
the following conditions:
518536
519-
Permission is hereby granted, free of charge, to any person obtaining
520-
a copy of this software and associated documentation files (the
521-
"Software"), to deal in the Software without restriction, including
522-
without limitation the rights to use, copy, modify, merge, publish,
523-
distribute, sublicense, and/or sell copies of the Software, and to
524-
permit persons to whom the Software is furnished to do so, subject to
525-
the following conditions:
537+
The above copyright notice and this permission notice shall be
538+
included in all copies or substantial portions of the Software.
526539
527-
The above copyright notice and this permission notice shall be
528-
included in all copies or substantial portions of the Software.
540+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
541+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
542+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
543+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
544+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
545+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
546+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
529547

530-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
531-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
532-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
533-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
534-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
535-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
536-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
537-
538-
#if !HAS_LIBC_BUILTIN(__builtin_memset)
539548
void* memset(void* dst, int c, usize n) {
540549
u8* s = dst;
541550
usize k;
@@ -567,77 +576,73 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
567576
*s = c;
568577
return dst;
569578
}
570-
#endif
571579

572-
#if !HAS_LIBC_BUILTIN(__builtin_memcpy)
573580
void* memcpy(void* restrict dst, const void* restrict src, usize n) {
574581
u8* d = dst;
575582
const u8* s = src;
576583
for (; n; n--)
577584
*d++ = *s++;
578585
return dst;
579586
}
580-
#endif
581587

582-
#if !HAS_LIBC_BUILTIN(__builtin_memmove)
583-
#if __has_attribute(__may_alias__)
584-
typedef __attribute__((__may_alias__)) usize WT;
585-
#define WS (sizeof(WT))
586-
#endif
587-
void* memmove(void *dest, const void *src, usize n) {
588-
char *d = dest;
589-
const char *s = src;
590-
if (d==s) return d;
591-
if ((uintptr)s-(uintptr)d-n <= -2*n) return memcpy(d, s, n);
592-
if (d<s) {
593-
#if __has_attribute(__may_alias__)
594-
if ((uintptr)s % WS == (uintptr)d % WS) {
595-
while ((uintptr)d % WS) {
596-
if (!n--) return dest;
597-
*d++ = *s++;
588+
589+
#if __has_attribute(__may_alias__)
590+
typedef __attribute__((__may_alias__)) usize WT;
591+
#define WS (sizeof(WT))
592+
#endif
593+
594+
void* memmove(void *dest, const void *src, usize n) {
595+
char *d = dest;
596+
const char *s = src;
597+
if (d==s) return d;
598+
if ((uintptr)s-(uintptr)d-n <= -2*n) return memcpy(d, s, n);
599+
if (d<s) {
600+
#if __has_attribute(__may_alias__)
601+
if ((uintptr)s % WS == (uintptr)d % WS) {
602+
while ((uintptr)d % WS) {
603+
if (!n--) return dest;
604+
*d++ = *s++;
605+
}
606+
for (; n>=WS; n-=WS, d+=WS, s+=WS) *(WT*)d = *(WT*)s;
598607
}
599-
for (; n>=WS; n-=WS, d+=WS, s+=WS) *(WT*)d = *(WT*)s;
600-
}
601-
#endif
602-
for (; n; n--) *d++ = *s++;
603-
} else {
604-
#if __has_attribute(__may_alias__)
605-
if ((uintptr)s % WS == (uintptr)d % WS) {
606-
while ((uintptr)(d+n) % WS) {
607-
if (!n--) return dest;
608-
d[n] = s[n];
608+
#endif
609+
for (; n; n--) *d++ = *s++;
610+
} else {
611+
#if __has_attribute(__may_alias__)
612+
if ((uintptr)s % WS == (uintptr)d % WS) {
613+
while ((uintptr)(d+n) % WS) {
614+
if (!n--) return dest;
615+
d[n] = s[n];
616+
}
617+
while (n>=WS) n-=WS, *(WT*)(d+n) = *(WT*)(s+n);
609618
}
610-
while (n>=WS) n-=WS, *(WT*)(d+n) = *(WT*)(s+n);
611-
}
612-
#endif
613-
while (n) n--, d[n] = s[n];
619+
#endif
620+
while (n) n--, d[n] = s[n];
621+
}
622+
return dest;
614623
}
615-
return dest;
616-
}
617-
#endif
618624

619-
#if !HAS_LIBC_BUILTIN(__builtin_memcmp)
625+
620626
int memcmp(const void* a, const void* b, usize n) {
621627
const u8* l = a, *r = b;
622628
for (; n && *l == *r; n--, l++, r++) {}
623629
return n ? *l - *r : 0;
624630
}
625-
#endif
626631

627-
#if !HAS_LIBC_BUILTIN(__builtin_strcmp)
632+
628633
int strcmp(const char* l, const char* r) {
629634
for (; *l==*r && *l; l++, r++);
630635
return *(unsigned char *)l - *(unsigned char *)r;
631636
}
632-
#endif
633637

634-
#if !HAS_LIBC_BUILTIN(__builtin_strlen)
638+
635639
usize strlen(const char* s) {
636640
const char* p = s;
637641
for (; *s; s++);
638642
return (usize)(uintptr)(s - p);
639643
}
640-
#endif
644+
645+
#endif // RSM_NO_CC_BUILTINS
641646

642647

643648
// --- END musl code ---

‎src/rsmimpl.h

+102-51
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,67 @@
66
#undef RSM_NO_INT_DEFS
77
#endif
88
#include "rsm.h"
9-
10-
typedef signed char i8;
11-
typedef unsigned char u8;
12-
typedef signed short i16;
13-
typedef unsigned short u16;
14-
typedef signed int i32;
15-
typedef unsigned int u32;
16-
typedef signed long long i64;
17-
typedef unsigned long long u64;
18-
typedef float f32;
19-
typedef double f64;
20-
typedef unsigned int uint;
21-
typedef signed long isize;
22-
typedef unsigned long usize;
23-
#ifdef __INTPTR_TYPE__
24-
typedef __INTPTR_TYPE__ intptr;
25-
typedef __UINTPTR_TYPE__ uintptr;
9+
#ifndef RSM_NO_LIBC
10+
// note that rsm.h includes <stdint.h> and <stddef.h>
11+
#include <sys/types.h> // ssize_t
12+
typedef int8_t i8;
13+
typedef uint8_t u8;
14+
typedef int16_t i16;
15+
typedef uint16_t u16;
16+
typedef int32_t i32;
17+
typedef uint32_t u32;
18+
typedef int64_t i64;
19+
typedef uint64_t u64;
20+
typedef size_t usize;
21+
typedef ssize_t isize;
22+
typedef intptr_t intptr;
23+
typedef uintptr_t uintptr;
2624
#else
27-
typedef signed long intptr;
28-
typedef unsigned long uintptr;
25+
typedef signed char i8;
26+
typedef unsigned char u8;
27+
typedef signed short i16;
28+
typedef unsigned short u16;
29+
typedef signed int i32;
30+
typedef unsigned int u32;
31+
typedef signed long long i64;
32+
typedef unsigned long long u64;
33+
#ifdef __INTPTR_MAX__
34+
#define INTPTR_MIN (-__INTPTR_MAX__-1L)
35+
#define INTPTR_MAX __INTPTR_MAX__
36+
#define UINTPTR_MAX __UINTPTR_MAX__
37+
#else
38+
#define INTPTR_MIN ISIZE_MIN
39+
#define INTPTR_MAX ISIZE_MAX
40+
#define UINTPTR_MAX USIZE_MAX
41+
#endif
42+
#ifdef __SIZE_TYPE__
43+
typedef __SIZE_TYPE__ usize;
44+
#if defined(__UINTPTR_MAX__) && defined(__INTPTR_TYPE__) && \
45+
__SIZE_MAX__ == __UINTPTR_MAX__
46+
typedef __INTPTR_TYPE__ isize;
47+
#else
48+
typedef signed long isize;
49+
#endif
50+
#else
51+
typedef unsigned long usize;
52+
typedef signed long isize;
53+
#endif
54+
#ifdef __INTPTR_TYPE__
55+
typedef __INTPTR_TYPE__ intptr;
56+
typedef __UINTPTR_TYPE__ uintptr;
57+
#else
58+
typedef signed long intptr;
59+
typedef unsigned long uintptr;
60+
#endif
2961
#endif
3062

63+
// because PRIu64 is sad
64+
typedef unsigned long long ull_t;
65+
typedef long long ill_t;
66+
67+
typedef float f32;
68+
typedef double f64;
69+
3170
#define I8_MAX 0x7f
3271
#define I16_MAX 0x7fff
3372
#define I32_MAX 0x7fffffff
@@ -44,16 +83,10 @@ typedef unsigned long usize;
4483
#define U16_MAX 0xffff
4584
#define U32_MAX 0xffffffff
4685
#define U64_MAX 0xffffffffffffffff
47-
#define USIZE_MAX (__LONG_MAX__ *2UL+1UL)
48-
49-
#ifdef __INTPTR_MAX__
50-
#define INTPTR_MIN (-__INTPTR_MAX__-1L)
51-
#define INTPTR_MAX __INTPTR_MAX__
52-
#define UINTPTR_MAX __UINTPTR_MAX__
86+
#ifdef __SIZE_MAX__
87+
#define USIZE_MAX __SIZE_MAX__
5388
#else
54-
#define INTPTR_MIN ISIZE_MIN
55-
#define INTPTR_MAX ISIZE_MAX
56-
#define UINTPTR_MAX USIZE_MAX
89+
#define USIZE_MAX (__LONG_MAX__ *2UL+1UL)
5790
#endif
5891

5992
#ifndef __cplusplus
@@ -112,6 +145,12 @@ typedef unsigned long usize;
112145
#define ATTR_PACKED
113146
#endif
114147

148+
#if __has_attribute(may_alias)
149+
#define ATTR_MAY_ALIAS __attribute__((__may_alias__))
150+
#else
151+
#define ATTR_MAY_ALIAS
152+
#endif
153+
115154
#ifdef __wasm__
116155
#define WASM_EXPORT __attribute__((visibility("default")))
117156
#define WASM_IMPORT __attribute__((visibility("default")))
@@ -133,6 +172,20 @@ typedef unsigned long usize;
133172
#define ATTR_FORMAT(...)
134173
#endif
135174

175+
// don't use __builtin_* compiler intrinsics for WASM
176+
#if defined(__wasm__) && !defined(__wasi__)
177+
#define RSM_NO_CC_BUILTINS 1
178+
#endif
179+
180+
// expose Linux/GNU specific libc APIs
181+
#ifdef __linux__
182+
#define _GNU_SOURCE
183+
#endif
184+
185+
#ifndef _Nonnull
186+
#define _Nonnull
187+
#endif
188+
136189
// RSM_LITTLE_ENDIAN=0|1
137190
#ifndef RSM_LITTLE_ENDIAN
138191
#if defined(__LITTLE_ENDIAN__) || \
@@ -142,7 +195,7 @@ typedef unsigned long usize;
142195
(defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
143196
#define RSM_LITTLE_ENDIAN 0
144197
#else
145-
#error Can't determine endianness -- please define RSM_LITTLE_ENDIAN=0|1
198+
#error "Can't determine endianness -- please define RSM_LITTLE_ENDIAN=0|1"
146199
#endif
147200
#endif
148201

@@ -211,15 +264,15 @@ typedef unsigned long usize;
211264
#define UNREACHABLE abort()
212265
#endif
213266

214-
#if defined(__clang__) || defined(__gcc__)
215-
#define _DIAGNOSTIC_IGNORE_PUSH(x) _Pragma("GCC diagnostic push") _Pragma(#x)
216-
#define DIAGNOSTIC_IGNORE_PUSH(STR) _DIAGNOSTIC_IGNORE_PUSH(GCC diagnostic ignored STR)
217-
#define DIAGNOSTIC_IGNORE_POP() _Pragma("GCC diagnostic pop")
218-
#else
219-
#define DIAGNOSTIC_IGNORE_PUSH(STR)
220-
#define DIAGNOSTIC_IGNORE_POP()
267+
#ifndef _Pragma
268+
#error no _Pragma
269+
#define _Pragma(x)
221270
#endif
222271

272+
#define _DIAGNOSTIC_IGNORE_PUSH(x) _Pragma("GCC diagnostic push") _Pragma(#x)
273+
#define DIAGNOSTIC_IGNORE_PUSH(STR) _DIAGNOSTIC_IGNORE_PUSH(GCC diagnostic ignored STR)
274+
#define DIAGNOSTIC_IGNORE_POP() _Pragma("GCC diagnostic pop")
275+
223276
#ifndef countof
224277
#define countof(x) \
225278
((sizeof(x)/sizeof(0[x])) / ((usize)(!(sizeof(x) % sizeof(0[x])))))
@@ -299,10 +352,10 @@ typedef unsigned long usize;
299352
// branchless ( on ? (flags | flag) : (flags & ~flag) )
300353
#define COND_FLAG(flags, flag, on) ({ \
301354
__typeof__(flags) flags__ = (flags); \
302-
(flags__ ^ ( (__typeof__(flags))-(!!(on)) ^ flags__ ) & (__typeof__(flags))(flag)); \
355+
(flags__ ^ (( (__typeof__(flags))-(!!(on)) ^ flags__ ) & (__typeof__(flags))(flag)));\
303356
})
304357
#define COND_FLAG_X(flags, flag, on) \
305-
((flags) ^ ( (__typeof__(flags))-(!!(on)) ^ (flags) ) & (__typeof__(flags))(flag))
358+
((flags) ^ (( (__typeof__(flags))-(!!(on)) ^ (flags) ) & (__typeof__(flags))(flag)))
306359

307360
// POISON constants are non-NULL addresses which will result in page faults on access.
308361
// Values match those of Linux.
@@ -352,7 +405,7 @@ typedef unsigned long usize;
352405
i16: __builtin_ctz, u16: __builtin_ctz, \
353406
i32: __builtin_ctz, u32: __builtin_ctz, \
354407
long: __builtin_ctzl, unsigned long: __builtin_ctzl, \
355-
i64: __builtin_ctzll, u64: __builtin_ctzll)(x)
408+
long long: __builtin_ctzll, unsigned long long: __builtin_ctzll)(x)
356409

357410
// int rsm_clz(ANYUINT x) counts leading zeroes in x,
358411
// starting at the most significant bit position.
@@ -363,7 +416,7 @@ typedef unsigned long usize;
363416
i16: __builtin_clz, u16: __builtin_clz, \
364417
i32: __builtin_clz, u32: __builtin_clz, \
365418
long: __builtin_clzl, unsigned long: __builtin_clzl, \
366-
i64: __builtin_clzll, u64: __builtin_clzll \
419+
long long: __builtin_clzll, unsigned long long: __builtin_clzll \
367420
)(x) - ( 32 - MIN_X(4, (int)sizeof(__typeof__(x)))*8 ) \
368421
)
369422
#define RSM_CLZ_X rsm_clz
@@ -376,7 +429,7 @@ typedef unsigned long usize;
376429
i16: __builtin_ffs, u16: __builtin_ffs, \
377430
i32: __builtin_ffs, u32: __builtin_ffs, \
378431
long: __builtin_ffsl, unsigned long: __builtin_ffsl, \
379-
i64: __builtin_ffsll, u64: __builtin_ffsll \
432+
long long: __builtin_ffsll, unsigned long long: __builtin_ffsll \
380433
)(x)
381434
#define RSM_FFS_X rsm_ffs
382435

@@ -644,46 +697,44 @@ typedef __builtin_va_list va_list;
644697
RSM_ASSUME_NONNULL_BEGIN
645698

646699
// minimal set of libc functions
647-
#define HAS_LIBC_BUILTIN(f) \
648-
(__has_builtin(f) && (!defined(__wasm__) || defined(__wasi__)))
649700

650-
#if HAS_LIBC_BUILTIN(__builtin_memset)
701+
#if __has_builtin(__builtin_memset) && !RSM_NO_CC_BUILTINS
651702
#define memset __builtin_memset
652703
#else
653704
void* memset(void* p, int c, usize n);
654705
#endif
655706

656-
#if HAS_LIBC_BUILTIN(__builtin_memcpy)
707+
#if __has_builtin(__builtin_memcpy) && !RSM_NO_CC_BUILTINS
657708
#define memcpy __builtin_memcpy
658709
#else
659710
void* memcpy(void* restrict dst, const void* restrict src, usize n);
660711
#endif
661712

662-
#if HAS_LIBC_BUILTIN(__builtin_memmove)
713+
#if __has_builtin(__builtin_memmove) && !RSM_NO_CC_BUILTINS
663714
#define memmove __builtin_memmove
664715
#else
665716
void* memmove(void* dest, const void* src, usize n);
666717
#endif
667718

668-
#if HAS_LIBC_BUILTIN(__builtin_memcmp)
719+
#if __has_builtin(__builtin_memcmp) && !RSM_NO_CC_BUILTINS
669720
#define memcmp __builtin_memcmp
670721
#else
671722
int memcmp(const void* l, const void* r, usize n);
672723
#endif
673724

674-
#if HAS_LIBC_BUILTIN(__builtin_strlen)
725+
#if __has_builtin(__builtin_strlen) && !RSM_NO_CC_BUILTINS
675726
#define strlen __builtin_strlen
676727
#else
677728
usize strlen(const char* s);
678729
#endif
679730

680-
#if HAS_LIBC_BUILTIN(__builtin_strcmp)
731+
#if __has_builtin(__builtin_strcmp) && !RSM_NO_CC_BUILTINS
681732
#define strcmp __builtin_strcmp
682733
#else
683734
int strcmp(const char* l, const char* r);
684735
#endif
685736

686-
#if defined(__wasm__) && !defined(__wasi__)
737+
#if RSM_NO_CC_BUILTINS
687738
int vsnprintf(char *restrict s, usize n, const char *restrict fmt, va_list ap);
688739
int snprintf(char* restrict s, usize n, const char* restrict fmt, ...);
689740
#endif // printf
@@ -713,7 +764,7 @@ void rsm_qsort(void* base, usize nmemb, usize size, rsm_qsort_cmp cmp, void* nul
713764

714765
#define tolower(c) ((c) | 0x20)
715766

716-
usize stru64(char buf[64], u64 v, u32 base);
767+
usize stru64(char* buf, u64 v, u32 base);
717768
rerr_t parseu64(const char* src, usize srclen, int base, u64* result, u64 cutoff);
718769

719770
rerr_t mmapfile(const char* filename, rmem_t* data_out);

‎src/sched.c

+24-23
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ enum PStatus {
106106
}
107107
if (t) {
108108
color = (char)('1' + (t->id % 6));
109-
fprintf(fp, "\e[1;3%cmT%-2llu\e[0m ", color, t->id);
109+
fprintf(fp, "\e[1;3%cmT%-2llu\e[0m ", color, (ull_t)t->id);
110110
} else {
111111
fprintf(fp, "\e[1;2mT- \e[0m ");
112112
}
@@ -304,7 +304,7 @@ static void p_runq_put(P* p, T* t, bool runnext) {
304304
// into oldnext, thus we can simply loop here without having to explicitly
305305
// load oldnext=p->runnext.
306306
}
307-
trace3("set p.runnext = T%llu", t->id);
307+
trace3("set p.runnext = T%llu", (ull_t)t->id);
308308
if (oldnext == NULL)
309309
return;
310310
// Kick the old runnext out to the regular run queue
@@ -316,7 +316,7 @@ static void p_runq_put(P* p, T* t, bool runnext) {
316316
u32 head = AtomicLoadAcq(&p->runqhead);
317317
u32 tail = p->runqtail;
318318
if (tail - head < P_RUNQSIZE) {
319-
trace3("set p.runq[%u] = T%llu", tail % P_RUNQSIZE, t->id);
319+
trace3("set p.runq[%u] = T%llu", tail % P_RUNQSIZE, (ull_t)t->id);
320320
p->runq[tail % P_RUNQSIZE] = t;
321321
// store memory_order_release makes the item available for consumption
322322
AtomicStoreRel(&p->runqtail, tail + 1);
@@ -357,7 +357,7 @@ static T* nullable p_runq_get(P* p, bool* inherit_time) {
357357
// trace3("loop2 tail != head; load p->runq[%u]", head % P_RUNQSIZE);
358358
T* t = p->runq[head % P_RUNQSIZE];
359359
// trace3("loop2 t => %p", t);
360-
// trace3("loop2 t => T%llu", t->id);
360+
// trace3("loop2 t => T%llu", (ull_t)t->id);
361361
if (AtomicCASRel(&p->runqhead, &head, head + 1)) // cas-release, commits consume
362362
return t;
363363
trace3("CAS failure; retry");
@@ -444,7 +444,7 @@ static rerr_t s_allt_add(rsched_t* s, T* t) {
444444
AtomicStore(&s->allt.ptr, mem.p, memory_order_release);
445445
}
446446

447-
trace3("add s.allt[%u] = T%llu", s->allt.len, t->id);
447+
trace3("add s.allt[%u] = T%llu", s->allt.len, (ull_t)t->id);
448448
s->allt.ptr[s->allt.len++] = t;
449449
AtomicStore(&s->allt.len, s->allt.len, memory_order_release);
450450

@@ -468,13 +468,13 @@ static u64 tctx_vaddr(u64 sp) {
468468
static tctx_t* nullable m_get_tctx(M* m, T* t) {
469469
// A suspended task's tctx is stored on the task's stack, just above SP
470470
u64 ctx_vaddr = tctx_vaddr(t->sp);
471-
assertf(ctx_vaddr >= t->stack_lo, "%llx, %llx", ctx_vaddr, t->stack_lo);
471+
assertf(ctx_vaddr >= t->stack_lo, "%llx, %llx", (ull_t)ctx_vaddr, (ull_t)t->stack_lo);
472472

473473
// get backing memory
474474
vm_cache_t* vm_cache = &m->vm_cache[VM_PERM_RW];
475475
uintptr haddr = VM_TRANSLATE(vm_cache, &m->s->vm_pagedir, ctx_vaddr, TCTX_ALIGN);
476476

477-
//dlog("load ctx from stack at vaddr 0x%llx (haddr %p)", ctx_vaddr, (void*)haddr);
477+
//dlog("load ctx from stack at vaddr 0x%llx (haddr %p)", (ull_t)ctx_vaddr, (void*)haddr);
478478
return (tctx_t*)haddr;
479479
}
480480

@@ -538,7 +538,7 @@ static void s_wakep(rsched_t* s) {
538538
// m_switchtask configures m to execute task t.
539539
// It first saves the current task's state, then restores the state of t.
540540
static void m_switchtask(M* m, T* nullable t) {
541-
if (t) trace("-> T%llu", t->id);
541+
if (t) trace("-> T%llu", (ull_t)t->id);
542542
else trace("-> T-");
543543

544544
assert(t != m->currt);
@@ -573,9 +573,10 @@ static T* nullable task_create(M* m, u64 stack_vaddr, usize stacksize, usize ins
573573
vm_cache_t* vm_cache = &m->vm_cache[VM_PERM_RW];
574574
void* stackptr =
575575
(void*)VM_TRANSLATE(vm_cache, &m->s->vm_pagedir, stack_vaddr, STK_ALIGN);
576-
assertf(stackptr != NULL, "stack memory not mapped for 0x%llx", stack_vaddr);
576+
assertf(stackptr != NULL, "stack memory not mapped for 0x%llx", (ull_t)stack_vaddr);
577577

578-
//dlog("stack 0x%llx => haddr %p ... %p", stack_vaddr, stackptr - stacksize, stackptr);
578+
//dlog("stack 0x%llx => haddr %p ... %p",
579+
// (ull_t)stack_vaddr, stackptr - stacksize, stackptr);
579580

580581
// space for T, below stack, with strongest alignment
581582
usize tsize = ALIGN2(sizeof(T), MAX(_Alignof(T), STK_ALIGN));
@@ -594,9 +595,9 @@ static T* nullable task_create(M* m, u64 stack_vaddr, usize stacksize, usize ins
594595
tctx_t* ctx = (tctx_t*)ALIGN2_FLOOR((uintptr)sp - sizeof(tctx_t), TCTX_ALIGN);
595596
ctx->iregs[RSM_MAX_REG - RSM_NTMPREGS - 1] = (u64)(uintptr)t; // CTX reg
596597

597-
//dlog("store ctx to stack at vaddr 0x%llx (haddr %p)", tctx_vaddr(t->sp), ctx);
598+
//dlog("store ctx to stack at vaddr 0x%llx (haddr %p)", (ull_t)tctx_vaddr(t->sp), ctx);
598599

599-
trace2("T@%p+%zu stack 0x%llx-0x%llx", t, tsize, t->stack_lo, t->stack_hi);
600+
trace2("T@%p+%zu stack 0x%llx-0x%llx", t, tsize, (ull_t)t->stack_lo, (ull_t)t->stack_hi);
600601

601602
return t;
602603
}
@@ -689,7 +690,7 @@ i64 task_spawn(T* t, usize newtask_pc, const u64 args[RSM_NARGREGS]) {
689690
T* newt = m_spawn(m, instrv, instrc, newtask_pc, stack_vaddr, stacksize, &err);
690691
if (!newt)
691692
return (i64)err;
692-
trace("-> T%llu (pc %lu)", newt->id, newtask_pc);
693+
trace("-> T%llu (pc %lu)", (ull_t)newt->id, newtask_pc);
693694
return (i64)newt->id;
694695
}
695696

@@ -952,7 +953,7 @@ static void p_freet_add(P* p, T* t) {
952953
assert_tstatus(t, T_DEAD);
953954

954955
u64 stacksize = t->stack_hi - t->stack_lo;
955-
trace3("T%llu -> P%u.freet (stacksize %llu)", t->id, p->id, stacksize);
956+
trace3("T%llu -> P%u.freet (stacksize %llu)", (ull_t)t->id, p->id, (ull_t)stacksize);
956957

957958
tlist_push(&p->freet, t);
958959

@@ -1255,7 +1256,7 @@ static stealresult_t m_steal_work(M* m, bool* inherit_time) {
12551256

12561257
P* p = assertnotnull(m->p);
12571258
rsched_t* s = m->s;
1258-
u32 steal_attempts = MIN(4, s->nprocs);
1259+
u32 steal_attempts = MIN(4u, s->nprocs);
12591260

12601261
for (u32 i = 0; i < steal_attempts; i++) {
12611262
trace3("attempt %u of %u", i+1, steal_attempts);
@@ -1289,7 +1290,7 @@ static stealresult_t m_steal_work(M* m, bool* inherit_time) {
12891290
// steal half of p2's runq
12901291
T* t = p_runq_steal(p, p2, is_final_attempt);
12911292
if (t) {
1292-
trace2("T%llu (stolen from P%u)", t->id, p2->id);
1293+
trace2("T%llu (stolen from P%u)", (ull_t)t->id, p2->id);
12931294
res.t = t;
12941295
goto end;
12951296
}
@@ -1379,7 +1380,7 @@ static T* nullable m_findrunnable(M* m, bool* inherit_time) {
13791380
trace3("try p.runq");
13801381
t = p_runq_get(p, inherit_time);
13811382
if (t) {
1382-
trace3("found T%llu on p.runq", t->id);
1383+
trace3("found T%llu on p.runq", (ull_t)t->id);
13831384
return t;
13841385
}
13851386

@@ -1390,7 +1391,7 @@ static T* nullable m_findrunnable(M* m, bool* inherit_time) {
13901391
t = s_runq_get(s, p, 0); // 0 means "move all to P"
13911392
mutex_unlock(&s->lock);
13921393
if (t) {
1393-
trace3("found T%llu on s.runq", t->id);
1394+
trace3("found T%llu on s.runq", (ull_t)t->id);
13941395
*inherit_time = false;
13951396
return t;
13961397
}
@@ -1434,7 +1435,7 @@ static T* nullable m_findrunnable(M* m, bool* inherit_time) {
14341435
t = s_runq_get(s, p, 0); // 0 means "move all to P"
14351436
assertnotnull(t); // lock held; runq.len not able to change
14361437
mutex_unlock(&s->lock);
1437-
trace3("found T%llu in s.runq", t->id);
1438+
trace3("found T%llu in s.runq", (ull_t)t->id);
14381439
*inherit_time = false;
14391440
return t;
14401441
}
@@ -1532,7 +1533,7 @@ static rerr_t m_schedule(M* m) {
15321533
mutex_lock(&s->lock);
15331534
t = s_runq_get(s, p, 1);
15341535
mutex_unlock(&s->lock);
1535-
if (t) trace2("random runq steal of T%llu", t->id);
1536+
if (t) trace2("random runq steal of T%llu", (ull_t)t->id);
15361537
}
15371538

15381539
// if M does not have an associated P, wait for a P to become available
@@ -1820,7 +1821,7 @@ static void dlog_memory_map(
18201821
(name), haddr__, (size)); \
18211822
} else { \
18221823
dlog(" %-7s %12lx %012llx-%012llx %8zu", \
1823-
(name), haddr__, vaddr__, vaddr_end__, (size)); \
1824+
(name), haddr__, (ull_t)vaddr__, (ull_t)vaddr_end__, (size)); \
18241825
} \
18251826
}
18261827

@@ -1975,7 +1976,7 @@ static rerr_t rsched_loadrom(
19751976
usize lo_nbyte = (stacksize + exeinfo_size) - hi_nbyte;
19761977
u64 lo_vaddr = STACK_VADDR - stacksize;
19771978
usize lo_npages = lo_nbyte / PAGE_SIZE;
1978-
//dlog("map %zu pages: 0x%llx (lazy)", lo_npages, lo_vaddr);
1979+
//dlog("map %zu pages: 0x%llx (lazy)", lo_npages, (ull_t)lo_vaddr);
19791980
err = vm_map(&s->vm_pagedir, 0, lo_vaddr, lo_npages, VM_PERM_RW);
19801981
if UNLIKELY(err) {
19811982
dlog("vm_map failed: %s", rerr_str(err));
@@ -1986,7 +1987,7 @@ static rerr_t rsched_loadrom(
19861987
// map the high-address pages of the stack WITH backing memory
19871988
u64 vaddr = lo_vaddr + lo_nbyte;
19881989
assertf(IS_ALIGN2(hi_nbyte, PAGE_SIZE), "%zu", hi_nbyte);
1989-
//dlog("map %zu pages: 0x%llx => %p", hi_nbyte/PAGE_SIZE, vaddr, (void*)haddr);
1990+
//dlog("map %zu pages: 0x%llx => %p", hi_nbyte/PAGE_SIZE, (ull_t)vaddr, (void*)haddr);
19901991
err = vm_map(&s->vm_pagedir, haddr, vaddr, hi_nbyte/PAGE_SIZE, VM_PERM_RW);
19911992
if UNLIKELY(err) {
19921993
dlog("vm_map failed: %s", rerr_str(err));

‎src/sched_exec.c

+20-18
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ static_assert(STK_MIN % STK_ALIGN == 0, "STK_MIN not aligned to STK_ALIGN");
3939
}
4040
static void exec_logstate(EXEC_PARAMS) {
4141
for (int i = 0; i < 6; i++)
42-
fprintf(stderr, REG_FMTVAL_PAT("%5llx"), REG_FMTVAL(i, iregs[i]));
42+
fprintf(stderr, REG_FMTVAL_PAT("%5llx"), REG_FMTVAL(i, (ull_t)iregs[i]));
4343
char buf[128];
4444
rsm_fmtinstr(buf, sizeof(buf), inv[pc], NULL, RSM_FMT_COLOR);
4545
fprintf(stderr, REG_FMTVAL_PAT("%6llx") " │ %3ld %s\n",
46-
REG_FMTVAL(RSM_MAX_REG, iregs[RSM_MAX_REG]), pc, buf);
46+
REG_FMTVAL(RSM_MAX_REG, (ull_t)iregs[RSM_MAX_REG]), pc, buf);
4747
}
4848
#ifdef TRACE_MEMORY
4949
#if defined(SCHED_TRACE)
@@ -82,17 +82,18 @@ enum execerr_t {
8282
char buf[2048];
8383
abuf_t s1 = abuf_make(buf, sizeof(buf)); abuf_t* b = &s1;
8484
pc--; // undo the increment to make pc point to the violating instruction
85+
ull_t a1 = (ull_t)arg1, a2 = (ull_t)arg2;
8586
#define _(ERR, fmt, args...) case ERR: abuf_fmt(b, fmt, ##args); break;
8687
switch ((enum execerr_t)err) {
87-
_(EX_E_UNALIGNED_STORE, "unaligned memory store %llx (align %llu B)", arg1, arg2)
88-
_(EX_E_UNALIGNED_ACCESS,"unaligned memory access %llx (align %llu B)", arg1, arg2)
89-
_(EX_E_UNALIGNED_STACK, "unaligned stack pointer SP=%llx (align %d B)", arg1, STK_ALIGN)
90-
_(EX_E_STACK_OVERFLOW, "stack overflow %llx (align %llu B)", arg1, arg2)
91-
_(EX_E_OOB_LOAD, "memory load out of bounds %llx (align %llu B)", arg1, arg2)
92-
_(EX_E_OOB_STORE, "memory store out of bounds %llx (align %llu B)", arg1, arg2)
93-
_(EX_E_OOB_PC, "PC out of bounds %llx", arg1)
94-
_(EX_E_OPNOI, "op %s does not accept immediate value", rop_name(arg1))
95-
_(EX_E_SHIFT_EXP, "shift exponent %llu is too large", arg1)
88+
_(EX_E_UNALIGNED_STORE, "unaligned memory store %llx (align %llu B)", a1, a2)
89+
_(EX_E_UNALIGNED_ACCESS,"unaligned memory access %llx (align %llu B)", a1, a2)
90+
_(EX_E_UNALIGNED_STACK, "unaligned stack pointer SP=%llx (align %d B)", a1, STK_ALIGN)
91+
_(EX_E_STACK_OVERFLOW, "stack overflow %llx (align %llu B)", a1, a2)
92+
_(EX_E_OOB_LOAD, "memory load out of bounds %llx (align %llu B)", a1, a2)
93+
_(EX_E_OOB_STORE, "memory store out of bounds %llx (align %llu B)", a1, a2)
94+
_(EX_E_OOB_PC, "PC out of bounds %llx", a1)
95+
_(EX_E_OPNOI, "op %s does not accept immediate value", rop_name(a1))
96+
_(EX_E_SHIFT_EXP, "shift exponent %llu is too large", a1)
9697
}
9798
#undef _
9899
abuf_c(b, '\n');
@@ -108,7 +109,7 @@ enum execerr_t {
108109
abuf_fmt(b, "\n R%u…%u", i, MIN(i+7, endi-1));
109110
abuf_fill(b, ' ', 10 - (b->len - len - 1));
110111
}
111-
abuf_fmt(b, " %8llx", iregs[i]);
112+
abuf_fmt(b, " %8llx", (ull_t)iregs[i]);
112113
}
113114

114115
abuf_terminate(b);
@@ -174,7 +175,7 @@ enum execerr_t {
174175
u64 value__ = VM_LOAD( \
175176
TYPE, &(t)->m->vm_cache[VM_PERM_RW], &(t)->m->s->vm_pagedir, vaddr__); \
176177
tracemem("LOAD %s 0x%llx (align %lu) => 0x%llx", \
177-
#TYPE, vaddr__, _Alignof(TYPE), value__); \
178+
#TYPE, (ull_t)vaddr__, _Alignof(TYPE), (ull_t)value__); \
178179
value__; \
179180
})
180181

@@ -183,7 +184,7 @@ enum execerr_t {
183184
u64 vaddr__ = (vaddr); \
184185
u64 value__ = (value); \
185186
tracemem("STORE %s 0x%llx (align %lu) => 0x%llx", \
186-
#TYPE, vaddr__, _Alignof(TYPE), value__); \
187+
#TYPE, (ull_t)vaddr__, _Alignof(TYPE), (ull_t)value__); \
187188
VM_STORE( \
188189
TYPE, &(t)->m->vm_cache[VM_PERM_RW], &(t)->m->s->vm_pagedir, vaddr__, value__); \
189190
}
@@ -267,9 +268,9 @@ static bool _syscall(T* t, u64* iregs, usize pc, u32 syscall_op) {
267268
if (nsec == 0)
268269
return true; // no-op
269270
enter_syscall(t);
270-
dlog("sleeping for %llu ns", nsec);
271+
dlog("sleeping for %llu ns", (ull_t)nsec);
271272
u64 remaining = rsm_nanosleep(nsec);
272-
dlog("rsm_nanosleep() => remaining %llu", remaining);
273+
dlog("rsm_nanosleep() => remaining %llu", (ull_t)remaining);
273274
iregs[0] = remaining;
274275
return exit_syscall(t, /*priority*/0);
275276
}
@@ -282,7 +283,7 @@ static bool _syscall(T* t, u64* iregs, usize pc, u32 syscall_op) {
282283
// —————————— arithmetic
283284

284285
static void on_overflow(T* t, usize pc, rop_t op, i64 x, i64 y, i64* dst) {
285-
char opch;
286+
char opch = '?';
286287
const char* typename = "i64";
287288

288289
switch (op) {
@@ -310,7 +311,8 @@ static void on_overflow(T* t, usize pc, rop_t op, i64 x, i64 y, i64* dst) {
310311
}
311312

312313
// TODO raise error in scheduler/current task
313-
panic("signed integer overflow: %lld %c %lld overflows %s", x, opch, y, typename);
314+
panic("signed integer overflow: %lld %c %lld overflows %s",
315+
(ill_t)x, opch, (ill_t)y, typename);
314316
}
315317

316318
// void CHECK_OVERFLOW(name OP, name T, T x, T y, T* dstptr)

‎src/sched_os.c

+2
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ uintptr m_spawn_osthread(M* m, rerr_t(*mainf)(M*)) {
5050
}
5151

5252
// create the thread, executing mainf
53+
DIAGNOSTIC_IGNORE_PUSH("-Wcast-function-type")
5354
pthread_t t;
5455
err = pthread_create(&t, &attr, (void*nullable(*_Nonnull)(void*nullable))mainf, m);
56+
DIAGNOSTIC_IGNORE_POP()
5557

5658
// restore signal mask
5759
sigprocmask(SIG_SETMASK, &sigset_prev, NULL);

‎src/time.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ WASM_IMPORT rerr_t unixtime(i64* sec, u64* nsec);
4646
WASM_IMPORT double wasm_nanotime(void);
4747
#endif
4848

49+
#if !defined(CLOCK_MONOTONIC)
50+
#error CLOCK_MONOTONIC not defined
51+
#endif
4952

5053
u64 nanotime(void) {
5154
#if defined(__APPLE__)
@@ -59,7 +62,7 @@ u64 nanotime(void) {
5962
// QueryPerformanceCounter
6063
#elif !defined(RSM_NO_LIBC)
6164
struct timeval tv;
62-
safecheckexpr(gettimeofday(&tv, nullptr), 0);
65+
safecheckexpr(gettimeofday(&tv, NULL), 0);
6366
return ((u64)(tv.tv_sec) * 1000000000) + ((u64)(tv.tv_usec) * 1000);
6467
#elif defined(__wasm__)
6568
return (u64)wasm_nanotime();

‎src/vm.c

+43-32
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static_assert(sizeof(vm_pte_t) == sizeof(u64), "vm_pte_t too large");
3838

3939
// vm_pte_t printf formatting
4040
#define PTE_FMT "(0x%llx)"
41-
#define PTE_FMTARGS(pte) (pte).outaddr
41+
#define PTE_FMTARGS(pte) ((ull_t)(pte).outaddr)
4242

4343

4444
// getbits returns the (right adjusted) n-bit field of x that begins at position p.
@@ -86,7 +86,7 @@ static vm_ptab_t nullable vm_ptab_create(rmm_t* mm) {
8686
vm_ptab_t ptab = rmm_allocpages(mm, VM_PTAB_SIZE / PAGE_SIZE);
8787
if UNLIKELY(ptab == NULL)
8888
return NULL;
89-
#ifdef VM_ZERO_PAGES
89+
#ifndef VM_ZERO_PAGES
9090
memset(ptab, 0, VM_PTAB_SIZE);
9191
#endif
9292
return ptab;
@@ -158,7 +158,7 @@ static vm_pte_t* nullable alloc_backing_page(vm_pagedir_t* pagedir, vm_pte_t* pt
158158
static vm_pte_t* nullable vm_pagedir_access(
159159
vm_pagedir_t* pagedir, u64 vfn, bool isaccess)
160160
{
161-
assertf(vfn <= VM_VFN_MAX, "invalid VFN 0x%llx", vfn);
161+
assertf(vfn <= VM_VFN_MAX, "invalid VFN 0x%llx", (ull_t)vfn);
162162
u32 bits = 0;
163163
u64 masked_vfn = vfn;
164164
vm_ptab_t ptab = pagedir->root;
@@ -168,12 +168,12 @@ static vm_pte_t* nullable vm_pagedir_access(
168168
mutex_lock(&pagedir->lock);
169169

170170
for (;;) {
171-
u64 index = getbits(masked_vfn, VFN_BITS - (1+bits), VM_PTAB_BITS);
171+
usize index = (usize)getbits(masked_vfn, VFN_BITS - (1+bits), VM_PTAB_BITS);
172172
pte = &ptab[index];
173173

174174
trace(
175-
"lookup vfn 0x%llx L %u; index %llu = getbits(0x%llx, %u-(1+%u), %u)",
176-
vfn+1, level, index, masked_vfn, VFN_BITS, bits, VM_PTAB_BITS);
175+
"lookup vfn 0x%llx L %u; index %zu = getbits(0x%llx, %u-(1+%u), %u)",
176+
(ull_t)vfn+1, level, index, (ull_t)masked_vfn, VFN_BITS, bits, VM_PTAB_BITS);
177177

178178
if (level == VM_PTAB_LEVELS) {
179179
if UNLIKELY(*(u64*)pte == 0) {
@@ -208,7 +208,8 @@ rerr_t vm_unmap(vm_pagedir_t* pagedir, u64 vaddr, usize npages) {
208208
// TODO: rewrite this function like vm_map (based on logic in vm_pagedir_access)
209209
u64 vfn = VM_VFN(vaddr);
210210

211-
trace("unmap 0x%llx (vfn 0x%llx, %zu pages)", VM_PAGE_ADDR(vaddr), vfn, npages);
211+
trace("unmap 0x%llx (vfn 0x%llx, %zu pages)",
212+
(ull_t)VM_PAGE_ADDR(vaddr), (ull_t)vfn, npages);
212213

213214
for (u64 vfn_end = vfn + npages; vfn < vfn_end; vfn++) {
214215
vm_pte_t* pte = vm_pagedir_access(pagedir, vfn, /*is_access*/false);
@@ -221,7 +222,7 @@ rerr_t vm_unmap(vm_pagedir_t* pagedir, u64 vaddr, usize npages) {
221222
}
222223

223224

224-
static vm_ptab_t nullable new_ptab(vm_pagedir_t* pagedir, vm_ptab_t parent, u64 index) {
225+
static vm_ptab_t nullable new_ptab(vm_pagedir_t* pagedir, vm_ptab_t parent, usize index) {
225226
vm_ptab_t ptab = vm_ptab_create(pagedir->mm);
226227
if UNLIKELY(!ptab) {
227228
// out of backing memory
@@ -233,8 +234,8 @@ static vm_ptab_t nullable new_ptab(vm_pagedir_t* pagedir, vm_ptab_t parent, u64
233234
u64 ptab_hfn = ((u64)(uintptr)ptab) >> PAGE_SIZE_BITS;
234235
parent[index] = (vm_pte_t){ .outaddr = ptab_hfn };
235236

236-
trace("allocated page table %p (HFN 0x%llx) +0x%lx at parent[%llu]",
237-
ptab, ptab_hfn, VM_PTAB_SIZE, index);
237+
trace("allocated page table %p (HFN 0x%llx) +0x%lx at parent[%zu]",
238+
ptab, (ull_t)ptab_hfn, VM_PTAB_SIZE, index);
238239

239240
assertf(IS_ALIGN2((u64)(uintptr)ptab, PAGE_SIZE),
240241
"ptab_create did not allocate vm_ptab_t on a page boundary (0x%lx/%u)",
@@ -248,7 +249,8 @@ rerr_t vm_map(
248249
vm_pagedir_t* pagedir, uintptr haddr, u64 vaddr, usize npages, vm_perm_t perm)
249250
{
250251
assertf(IS_ALIGN2((uintptr)haddr, PAGE_SIZE), "haddr 0x%lx not page aligned", haddr);
251-
assertf(vaddr >= VM_ADDR_MIN && VM_ADDR_MAX >= vaddr, "invalid vaddr 0x%llx", vaddr);
252+
assertf(vaddr >= VM_ADDR_MIN && VM_ADDR_MAX >= vaddr,
253+
"invalid vaddr 0x%llx", (ull_t)vaddr);
252254

253255
if (npages == 0)
254256
return 0;
@@ -265,12 +267,17 @@ rerr_t vm_map(
265267
u64 masked_vfn = vfn;
266268
vm_ptab_t ptab = pagedir->root;
267269
u8 level = 1;
268-
u64 index;
270+
usize index;
271+
269272

270273
visit_next_ptab:
271-
index = getbits(masked_vfn, VFN_BITS - (1+bits), VM_PTAB_BITS);
274+
index = (usize)getbits(masked_vfn, VFN_BITS - (1+bits), VM_PTAB_BITS);
275+
272276
pte = &ptab[index];
273277

278+
if (ptab == NULL) panic("NULL ptab");
279+
if (pte == NULL) panic("NULL pte at index %zu", index);
280+
274281
if (level < VM_PTAB_LEVELS) {
275282
// page table branch
276283
bits += VM_PTAB_BITS;
@@ -286,18 +293,20 @@ rerr_t vm_map(
286293
// traverse existing table
287294
assert(pte->outaddr != 0);
288295
ptab = (vm_ptab_t)(uintptr)(pte->outaddr << PAGE_SIZE_BITS);
296+
if (ptab == NULL) panic("NULL ptab (2)");
289297
}
290298
goto visit_next_ptab;
291299
}
292300

293301
// page table leaf entry
294302
assert(npages > 0);
295303
for (;;) {
296-
trace("map 0x%llx => 0x%lx %s (vfn 0x%llx, ptab[%llu])",
297-
VM_VFN_VADDR(vfn), haddr, vm_perm_str(perm), vfn, index);
304+
trace("map 0x%llx => 0x%lx %s (vfn 0x%llx, ptab[%zu])",
305+
(ull_t)VM_VFN_VADDR(vfn), haddr, vm_perm_str(perm), (ull_t)vfn, index);
298306

299307
if UNLIKELY(*(u64*)pte) {
300-
dlog("trying to map already-mapped page at vaddr 0x%llx", VM_VFN_VADDR(vfn));
308+
dlog("trying to map already-mapped page at vaddr 0x%llx",
309+
(ull_t)VM_VFN_VADDR(vfn));
301310
err = rerr_exists;
302311
goto end;
303312
}
@@ -363,42 +372,44 @@ void vm_cache_invalidate(vm_cache_t* cache, u64 vaddr, usize npages) {
363372

364373
// returns vm_cache_ent_t.haddr_diff
365374
static u64 vm_cache_add(vm_cache_t* cache, u64 vpaddr, uintptr hpaddr) {
366-
assertf(IS_ALIGN2(vpaddr, PAGE_SIZE), "vpaddr not a page address 0x%llx", vpaddr);
367-
assertf(IS_ALIGN2(hpaddr, PAGE_SIZE), "hpaddr not a page address %p", (void*)hpaddr);
375+
assertf(IS_ALIGN2(vpaddr, PAGE_SIZE),
376+
"vpaddr not a page address 0x%llx", (ull_t)vpaddr);
377+
assertf(IS_ALIGN2(hpaddr, PAGE_SIZE),
378+
"hpaddr not a page address %p", (void*)hpaddr);
368379

369380
vm_cache_ent_t* entry = VM_CACHE_ENTRY(cache, vpaddr);
370381
entry->haddr_diff = (u64)hpaddr - vpaddr;
371382
entry->tag = vpaddr;
372383

373384
trace("%s 0x%llx => {.haddr_diff=0x%llx, .tag=0x%llx}",
374-
__FUNCTION__, vpaddr, entry->haddr_diff, entry->tag);
385+
__FUNCTION__, (ull_t)vpaddr, (ull_t)entry->haddr_diff, (ull_t)entry->tag);
375386

376387
return entry->haddr_diff;
377388
}
378389

379390

380391
// returns vm_cache_ent_t.haddr_diff
381392
u64 _vm_cache_miss(vm_cache_t* cache, vm_pagedir_t* pagedir, u64 vaddr, vm_op_t op) {
382-
trace("%s 0x%llx op=0x%x", __FUNCTION__, vaddr, op);
393+
trace("%s 0x%llx op=0x%x", __FUNCTION__, (ull_t)vaddr, op);
383394

384395
// check validity
385396
if UNLIKELY(VM_ADDR_MIN > vaddr || vaddr > VM_ADDR_MAX) {
386-
panic("invalid address 0x%llx (out of range)", vaddr); // FIXME
397+
panic("invalid address 0x%llx (out of range)", (ull_t)vaddr); // FIXME
387398
return 0;
388399
}
389400

390401
// check alignment
391402
if UNLIKELY(!IS_ALIGN2(vaddr, VM_OP_ALIGNMENT(op))) {
392403
const char* opname = VM_OP_TYPE(op) == VM_OP_LOAD ? "load from" : "store to";
393-
panic("misaligned %uB %s 0x%llx", VM_OP_ALIGNMENT(op), opname, vaddr); // FIXME
404+
panic("misaligned %uB %s 0x%llx", VM_OP_ALIGNMENT(op), opname, (ull_t)vaddr);// FIXME
394405
}
395406

396407
// get page table entry for the virtual page address (lookup via VFN)
397408
vm_pte_t* pte = vm_pagedir_access(pagedir, VM_VFN(vaddr), /*is_access*/true);
398409

399410
// check if the lookup failed
400411
if UNLIKELY(!pte) {
401-
panic("invalid address 0x%llx (not mapped)", vaddr);
412+
panic("invalid address 0x%llx (not mapped)", (ull_t)vaddr);
402413
return 0;
403414
}
404415

@@ -410,8 +421,8 @@ u64 _vm_cache_miss(vm_cache_t* cache, vm_pagedir_t* pagedir, u64 vaddr, vm_op_t
410421
if UNLIKELY(!VM_PERM_CHECK(hasperm, wantperm)) {
411422
trace("wantperm %s not in hasperm %s", vm_perm_str(wantperm), vm_perm_str(hasperm));
412423
if (VM_OP_TYPE(op) == VM_PERM_R)
413-
panic("store to read-protected address 0x%llx", vaddr);
414-
panic("store to read-only address 0x%llx", vaddr);
424+
panic("store to read-protected address 0x%llx", (ull_t)vaddr);
425+
panic("store to read-only address 0x%llx", (ull_t)vaddr);
415426
return 0;
416427
}
417428

@@ -422,7 +433,7 @@ u64 _vm_cache_miss(vm_cache_t* cache, vm_pagedir_t* pagedir, u64 vaddr, vm_op_t
422433
uintptr hpaddr = (uintptr)(pte->outaddr << PAGE_SIZE_BITS);
423434
u64 vpaddr = VM_PAGE_ADDR(vaddr);
424435

425-
trace("%s 0x%llx -> %p", __FUNCTION__, vaddr, (void*)hpaddr);
436+
trace("%s 0x%llx -> %p", __FUNCTION__, (ull_t)vaddr, (void*)hpaddr);
426437

427438
if (pte->uncacheable)
428439
return (u64)hpaddr - vpaddr; // vm_cache_ent_t.haddr_diff
@@ -438,8 +449,8 @@ static void test_vm() {
438449
dlog("PAGE_SIZE: %5u", PAGE_SIZE);
439450
dlog("PAGE_SIZE_BITS: %5u", PAGE_SIZE_BITS);
440451
dlog("VM_ADDR_BITS: %5u", VM_ADDR_BITS);
441-
dlog("VM_ADDR_MIN…MAX: 0x%llx … 0x%llx", VM_ADDR_MIN, VM_ADDR_MAX);
442-
dlog("VFN_BITS: %5u", VFN_BITS);
452+
dlog("VM_ADDR_MIN…MAX: 0x%llx … 0x%llx", (ull_t)VM_ADDR_MIN, (ull_t)VM_ADDR_MAX);
453+
dlog("VFN_BITS: %5u", VFN_BITS);
443454
dlog("VM_PTAB_LEVELS: %5u", VM_PTAB_LEVELS);
444455
dlog("VM_PTAB_BITS: %5u", VM_PTAB_BITS);
445456

@@ -516,12 +527,12 @@ static void test_vm() {
516527
rerr_t err = vm_map(pagedir, (uintptr)haddr, vaddr, npages, perm);
517528
assertf(err == 0, "%s", rerr_str(err));
518529

519-
dlog("VM_STORE(u32, 0x%llx, %u)", vaddr, value);
530+
dlog("VM_STORE(u32, 0x%llx, %u)", (ull_t)vaddr, value);
520531
VM_STORE(u32, cache_rw, pagedir, vaddr, value);
521532
value = VM_LOAD(u32, cache_rw, pagedir, vaddr);
522-
dlog("VM_LOAD(u32, 0x%llx) => %u", vaddr, value);
533+
dlog("VM_LOAD(u32, 0x%llx) => %u", (ull_t)vaddr, value);
523534
value = VM_LOAD(u32, cache_rw, pagedir, vaddr);
524-
dlog("VM_LOAD(u32, 0x%llx) => %u", vaddr, value);
535+
dlog("VM_LOAD(u32, 0x%llx) => %u", (ull_t)vaddr, value);
525536

526537
// loading an invalid address
527538
//VM_LOAD(u64, cache_rw, pagedir, 0xffffffffffffffffllu); // error
@@ -538,7 +549,7 @@ static void test_vm() {
538549
// writing to a read-only page fails
539550
err = vm_map(pagedir, 0lu, vaddr, npages, VM_PERM_R);
540551
assertf(err == 0, "%s", rerr_str(err));
541-
VM_LOAD(u32, cache_r, pagedir, vaddr); // ok
552+
value = VM_LOAD(u32, cache_r, pagedir, vaddr); // ok
542553
//VM_STORE(u32, cache_rw, pagedir, vaddr, value); // error
543554

544555
rmm_freepages(mm, haddr);

‎src/vm.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ RSM_ASSUME_NONNULL_BEGIN
1818
// VM_ADDR_PAGE_MASK: AND with vaddr to get the virtual page address
1919
// e.g. 1111111111111111111111111111111111111111111111111111000000000000
2020
#define VM_ADDR_BITS 48u /* 256 TiB */
21-
#define VM_ADDR_MIN (1llu << PAGE_SIZE_BITS)
22-
#define VM_ADDR_MAX ((1llu << VM_ADDR_BITS) - 1llu)
23-
#define VM_ADDR_OFFS_MASK ((u64)PAGE_SIZE - 1llu)
24-
#define VM_ADDR_PAGE_MASK ( ~0llu ^ ((u64)PAGE_SIZE - 1llu) )
21+
#define VM_ADDR_MIN ((u64)( 1llu << PAGE_SIZE_BITS ))
22+
#define VM_ADDR_MAX ((u64)( (1llu << VM_ADDR_BITS) - 1llu ))
23+
#define VM_ADDR_OFFS_MASK ((u64)( (ull_t)PAGE_SIZE - 1llu ))
24+
#define VM_ADDR_PAGE_MASK ((u64)( ~0llu ^ ((u64)PAGE_SIZE - 1llu) ))
2525

2626
// page table constants
2727
// VM_PTAB_BITS: bits per page table; a divisor of VM_VFN_BITS.

0 commit comments

Comments
 (0)
Please sign in to comment.