Skip to content

Commit 1b275ce

Browse files
committed
0.9.1 --- the second register comes back from every call
This kernel returns a second value in x1 (rdx on x86_64) from every system call, and the wrapper declared that register an input only. An optimizing compiler therefore kept the first argument there across the call: the preopen table stored the address of "/" from x1 after openat had cleared it, and every program built with --release faulted in kal_fs_preopen before main. The register is now an output as well. -fno-builtin keeps a counting loop from becoming strlen, and CI runs this package's tests and the independence check in both profiles.
1 parent 5ddb0e0 commit 1b275ce

3 files changed

Lines changed: 32 additions & 11 deletions

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,19 +227,27 @@ jobs:
227227
#
228228
# The step is openkal-linux's, unchanged, including the assertion that
229229
# every suite ran: a suite that discovered nothing reports success.
230+
# ⚠️ AND IN BOTH PROFILES. Until 0.9.1 every program built with --release
231+
# faulted before `main': the system-call wrapper declared x1 an input
232+
# only, this kernel returns a second value there, and an optimizing
233+
# compiler kept an argument in it across the call. The dev profile keeps
234+
# nothing in a register across a call and never showed it.
230235
- name: This package's own tests
231236
run: |
232237
set -euo pipefail
233-
mcpp test 2>&1 | tee tests.log
238+
for profile in dev release; do
239+
echo "--- profile $profile"
240+
mcpp test --profile "$profile" 2>&1 | tee tests.log
234241
# The list is derived from the files present rather than written out
235242
# here: a hand-written list names the suites that existed when it was
236243
# written, and one added afterwards escapes the assertion silently.
237244
missing=0
238245
for f in tests/*.cpp; do
239246
name="$(basename "$f" .cpp)"
240-
grep -q "^$name \.\.\. ok" tests.log || { echo "did not run or did not pass: $name" >&2; missing=1; }
247+
grep -q "^$name \.\.\. ok" tests.log || { echo "did not run or did not pass: $name ($profile)" >&2; missing=1; }
241248
done
242249
test "$missing" -eq 0
250+
done
243251
244252
# The other architecture, as far as this system allows it to be reached.
245253
#
@@ -279,7 +287,11 @@ jobs:
279287
# library through a macro.
280288
- name: The objects reference nothing of a C library but the two named
281289
run: |
282-
rm -rf target && mcpp build --features standalone
290+
# Both profiles: an optimizing compiler turns a counting loop into
291+
# `strlen', which the dev profile never shows (hence -fno-builtin).
292+
for profile in dev release; do
293+
echo "--- profile $profile"
294+
rm -rf target && mcpp build --features standalone --profile "$profile"
283295
objs="$(find target -path '*/obj/*' -name '*.o' ! -name '*.m.o' ! -name 'mcpp_*')"
284296
test -n "$objs" || { echo "no objects were found; the check would pass vacuously" >&2; exit 1; }
285297
@@ -326,7 +338,8 @@ jobs:
326338
done
327339
done
328340
test "$bad" -eq 0
329-
echo "the implementation reaches nothing of a C library but the two names that are named"
341+
echo "the implementation reaches nothing of a C library but the two names that are named ($profile)"
342+
done
330343
331344
# A checker is only useful if it fails when it should.
332345
- name: The independence check detects a dependence

mcpp.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
namespace = "mcpplibs"
33
name = "openkal-macos"
4-
version = "0.9.0"
4+
version = "0.9.1"
55
description = "An implementation of openkal for macOS, written on the kernel's own calls. Its purpose is as much to test the specification as to be used."
66
license = "Apache-2.0"
77

@@ -28,7 +28,7 @@ openkal = "0.12.0"
2828
# consumers rather than parts of the implementation.
2929
flags = [
3030
{ glob = "src/**", cxxflags = ["-fno-exceptions", "-fno-rtti",
31-
"-fno-stack-protector"] },
31+
"-fno-stack-protector", "-fno-builtin"] },
3232
]
3333

3434
[features]

src/sys.h

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,16 @@ inline okm_long sys(okm_long n, okm_long a = 0, okm_long b = 0, okm_long c = 0,
5454
register okm_long x4 __asm__("x4") = e;
5555
register okm_long x5 __asm__("x5") = f;
5656
okm_long failed;
57-
__asm__ __volatile__("svc #0x80\n\tcset %1, cs"
58-
: "+r"(x0), "=r"(failed)
59-
: "r"(x16), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
57+
// ⚠️⚠️ THE SECOND REGISTER COMES BACK TOO, AND UNTIL 0.9.1 IT WAS DECLARED AN
58+
// INPUT ONLY. This kernel returns a second value in x1 from every call ---
59+
// the two calls below read it --- and writes it whether or not the call has
60+
// one. Declared as an input, x1 was assumed to survive, and an optimizing
61+
// compiler kept the first argument there: the preopen table stored the
62+
// address of "/" from x1 after `openat' had cleared it, and every program
63+
// built with --release faulted in `kal_fs_preopen' before `main'.
64+
__asm__ __volatile__("svc #0x80\n\tcset %2, cs"
65+
: "+r"(x0), "+r"(x1), "=r"(failed)
66+
: "r"(x16), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
6067
: "memory", "cc");
6168
return failed ? -x0 : x0;
6269
}
@@ -71,9 +78,10 @@ inline okm_long sys(okm_long n, okm_long a = 0, okm_long b = 0, okm_long c = 0,
7178
register okm_long r10 __asm__("r10") = d;
7279
register okm_long r8 __asm__("r8") = e;
7380
register okm_long r9 __asm__("r9") = f;
81+
// The second value comes back in rdx, as x1 above: an output as well.
7482
__asm__ __volatile__("syscall"
75-
: "=a"(r), "=@ccc"(failed)
76-
: "a"(n | 0x2000000L), "D"(a), "S"(b), "d"(c),
83+
: "=a"(r), "+d"(c), "=@ccc"(failed)
84+
: "a"(n | 0x2000000L), "D"(a), "S"(b),
7785
"r"(r10), "r"(r8), "r"(r9)
7886
: "rcx", "r11", "memory", "cc");
7987
return failed ? -r : r;

0 commit comments

Comments
 (0)