boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs

commit 2f343a495eeffb8e75e24123a3b7b1527401af2f
parent b280ec862a18b1cedc49854477f5297ea99a9146
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 21 Apr 2026 07:13:36 -0700

kaem-minimal: P1 port of stage0-posix line-oriented shell

Tokenize each line, clone(SIGCHLD)+execve+waitid the command, abort on
non-zero child status. Intended as a future replacement for `sh -ec '…'`
inside the podman invocations; not wired into the Makefile yet.

Normalize the syscall surface in p1_gen.py along the way: drop the
ad-hoc `P1_SYSOPEN` (it used `open` on amd64 but `openat` on arm64/rv64
and silently skipped flags/mode on amd64) in favor of a uniform
`SYS_OPENAT` + `P1_SYSCALL` with explicit dirfd/flags/mode. Add
portability notes in the SYS_NUM table covering fork (amd64-only),
wait4 (32-bit compat only), open (amd64-only), and the amd64 vs
arm64/rv64 clone arg4/5 swap.

Works around an amd64-M0 quirk: M0 allocates a fixed 256-byte buffer
for each '…' quoted literal and writes opening-quote + every content
char, so >128 hex chars per line overflows by 1 and eventually tramples
the heap. Keep zero-fill data sections chunked to ≤128 hex chars/line.

kaem.run is a smoke-test fixture; `make PROG=kaem-minimal run` drives
it through /bin/echo and /bin/true identically on all three arches.

Diffstat:
Akaem-minimal.M1 | 1313+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Akaem.run | 3+++
Mp1_gen.py | 51++++++++++++++++++++++++++-------------------------
3 files changed, 1342 insertions(+), 25 deletions(-)

diff --git a/kaem-minimal.M1 b/kaem-minimal.M1 @@ -0,0 +1,1313 @@ +## kaem-minimal.M1 — P1 port of stage0-posix's kaem-minimal. +## +## Line-oriented shell: for each non-blank, non-comment line, tokenize +## and clone+execve+wait4. Aborts on non-zero child status. +## +## Grammar (matches stage0-posix/High Level Prototypes/kaem-minimal.c): +## ' ' / '\t' → token separator +## '\n' → end of command +## '#' → rest of line is a comment +## '"..."' → raw string; newlines, #, spaces kept literal +## '\\<c>' → drops backslash and the following char, ends token +## +## Usage: +## kaem-minimal [script] (default: kaem.run) +## +## Deviations from full kaem: no ${VAR} expansion, no VAR=value envars, +## no PATH search, no builtins (cd/echo/set/exec/if/…), no pipes, no +## redirection. "Read a line, exec it, check status" — enough to drive +## the P1 build pipeline in place of `sh -ec '…'`. +## +## Syscall surface (8): read, write, close, exit, openat, clone, execve, +## waitid. Uses openat(AT_FDCWD, …) because `open` is amd64-only; uses +## clone(SIGCHLD) instead of fork and waitid instead of wait4 because +## aarch64/riscv64 don't expose fork/wait4 in the asm-generic table. +## +## Buffers live in the single PT_LOAD segment (flags=7 = RWX), zero- +## filled at build time — the ELF loader maps them into writable pages. + + +## ---- _start ---------------------------------------------------------- +## argv/envp walk on entry: kernel layout at sp is +## [sp+0] argc +## [sp+8..] argv[0..argc-1], then NULL +## [after] envp[0..k-1], then NULL +## So envp = sp + 8*(argc+2). +:_start + P1_MOV_R3_SP + P1_LD_R0_R3_0 ## r0 = argc + + ## envp = sp + 8*(argc+2). Save for execve later. + P1_ADDI_R1_R0_2 + P1_SHLI_R1_R1_3 + P1_ADD_R2_R3_R1 ## r2 = envp pointer + P1_LI_R1 + &envp_ptr + P1_ST_R2_R1_0 + + ## filename = argc>=2 ? argv[1] : "kaem.run" + P1_LI_R1 + '02000000' + P1_LI_BR + &_start_default_script + P1_BLT_R0_R1 ## argc < 2 → default + P1_LD_R2_R3_16 ## r2 = argv[1] + P1_LI_BR + &_start_open_script + P1_B + +:_start_default_script + P1_LI_R2 + &default_filename + +:_start_open_script + ## openat(AT_FDCWD=-100, path=r2, flags=O_RDONLY=0, mode=0) + ## LI zero-extends, but the kernel reads dirfd as int32 — low 32 + ## bits 0xFFFFFF9C decode as -100 on all three arches. + P1_LI_R0 + SYS_OPENAT + P1_LI_R1 + '9CFFFFFF' + P1_LI_R3 + '00000000' + P1_LI_R4 + '00000000' + P1_SYSCALL ## r0 = fd or <0 errno + + ## fd < 0 → openfail + P1_LI_R1 + '00000000' + P1_LI_BR + &_start_openfail + P1_BLT_R0_R1 + + ## Slurp the whole file into read_buf. + P1_LI_R1 + &script_fd + P1_ST_R0_R1_0 ## stash fd so we can close after read + + P1_MOV_R1_R0 ## r1 = fd + P1_LI_R2 + &read_buf ## r2 = buf + P1_LI_R3 + &read_buf_end + P1_SUB_R3_R3_R2 ## r3 = capacity + P1_LI_BR + &read_file_all + P1_CALL ## r0 = bytes_read + + P1_LI_R1 + &src_len + P1_ST_R0_R1_0 + P1_LI_R1 + &src_pos + P1_LI_R2 + '00000000' + P1_ST_R2_R1_0 + + ## close(fd) + P1_LI_R0 + SYS_CLOSE + P1_LI_R1 + &script_fd + P1_LD_R1_R1_0 + P1_SYSCALL + +:_start_loop + ## Per-command reset. + P1_LI_R1 + &token_count + P1_LI_R2 + '00000000' + P1_ST_R2_R1_0 + P1_LI_R1 + &token_arena_next + P1_LI_R2 + &token_arena + P1_ST_R2_R1_0 + P1_LI_R1 + &current_token_ptr + P1_LI_R2 + '00000000' + P1_ST_R2_R1_0 + + ## Peek first; EOF → done. + P1_LI_BR + &peek_char + P1_CALL + P1_LI_R1 + '00000000' + P1_ADDI_R1_R1_NEG1 + P1_LI_BR + &_start_done + P1_BEQ_R0_R1 + + ## Tokenize one logical command (until '\n' or EOF). + P1_LI_BR + &collect_command + P1_CALL + + ## No tokens → blank or all-comment line; skip spawn. + P1_LI_R1 + &token_count + P1_LD_R1_R1_0 + P1_LI_R2 + '00000000' + P1_LI_BR + &_start_loop + P1_BEQ_R1_R2 + + P1_LI_BR + &emit_verbose + P1_CALL + + P1_LI_BR + &spawn_and_wait + P1_CALL + + P1_LI_BR + &_start_loop + P1_B + +:_start_done + P1_LI_R0 + SYS_EXIT + P1_LI_R1 + '00000000' + P1_SYSCALL + +:_start_openfail + P1_LI_R0 + SYS_WRITE + P1_LI_R1 + '02000000' + P1_LI_R2 + &msg_openfail + P1_LI_R3 + &msg_openfail_end + P1_SUB_R3_R3_R2 + P1_SYSCALL + P1_LI_R0 + SYS_EXIT + P1_LI_R1 + '01000000' + P1_SYSCALL + + +## ---- read_file_all(r1=fd, r2=buf, r3=cap) -> r0 = total_bytes ------ +## Read loop. r4-r7 are callee-saved AND preserved across SYSCALL, so +## we can park state there across each read() call. No PROLOGUE needed: +## we only issue syscalls, never CALL. +:read_file_all + P1_MOV_R4_R1 ## r4 = fd + P1_MOV_R5_R2 ## r5 = cur buf ptr + P1_MOV_R6_R3 ## r6 = remaining capacity + P1_LI_R7 + '00000000' ## r7 = total_read + +:read_file_all_loop + ## Capacity exhausted → stop (caller already sized generously). + P1_LI_R1 + '00000000' + P1_LI_BR + &read_file_all_done + P1_BEQ_R6_R1 + + P1_LI_R0 + SYS_READ + P1_MOV_R1_R4 + P1_MOV_R2_R5 + P1_MOV_R3_R6 + P1_SYSCALL ## r0 = n (0=EOF, <0=err) + + ## n <= 0 → done. Check < 0 first, then == 0. + P1_LI_R1 + '00000000' + P1_LI_BR + &read_file_all_done + P1_BLT_R0_R1 + P1_LI_BR + &read_file_all_done + P1_BEQ_R0_R1 + + P1_ADD_R5_R5_R0 ## buf += n + P1_SUB_R6_R6_R0 ## cap -= n + P1_ADD_R7_R7_R0 ## total += n + P1_LI_BR + &read_file_all_loop + P1_B + +:read_file_all_done + P1_MOV_R0_R7 + P1_RET + + +## ---- peek_char() -> r0 = byte (0..255) or -1 on EOF ---------------- +:peek_char + P1_LI_R1 + &src_pos + P1_LD_R1_R1_0 ## r1 = pos + P1_LI_R2 + &src_len + P1_LD_R2_R2_0 ## r2 = len + P1_LI_BR + &peek_char_inb + P1_BLT_R1_R2 + P1_LI_R0 + '00000000' + P1_ADDI_R0_R0_NEG1 + P1_RET +:peek_char_inb + P1_LI_R2 + &read_buf + P1_ADD_R2_R2_R1 ## r2 = &read_buf[pos] + P1_LB_R0_R2_0 + P1_RET + + +## ---- advance_char() — consume current char ------------------------ +:advance_char + P1_LI_R1 + &src_pos + P1_LD_R2_R1_0 + P1_ADDI_R2_R2_1 + P1_ST_R2_R1_0 + P1_RET + + +## ---- arena_putc(r1 = byte) ---------------------------------------- +## Append one byte to the token_arena at token_arena_next, bump the +## cursor. Opens a new token (sets current_token_ptr) if none is open. +:arena_putc + P1_LI_R2 + &current_token_ptr + P1_LD_R3_R2_0 ## r3 = current_token_ptr + P1_LI_R0 + '00000000' + P1_LI_BR + &arena_putc_have_open + P1_BNE_R3_R0 + ## No open token — open one: current_token_ptr = token_arena_next. + P1_LI_R3 + &token_arena_next + P1_LD_R3_R3_0 + P1_ST_R3_R2_0 + +:arena_putc_have_open + P1_LI_R2 + &token_arena_next + P1_LD_R3_R2_0 ## r3 = cursor + P1_SB_R1_R3_0 ## *cursor = byte + P1_ADDI_R3_R3_1 + P1_ST_R3_R2_0 ## cursor++ + P1_RET + + +## ---- end_token() — close the currently open token if any --------- +## Null-terminates the token in arena, records its start ptr in +## argv_out[token_count], bumps token_count, clears current_token_ptr. +## No-op if no token is open (e.g. trailing separator). +:end_token + P1_LI_R1 + &current_token_ptr + P1_LD_R2_R1_0 ## r2 = start ptr (or 0) + P1_LI_R3 + '00000000' + P1_LI_BR + &end_token_none + P1_BEQ_R2_R3 + + ## Write NUL to arena[cursor], bump cursor. + P1_LI_R1 + &token_arena_next + P1_LD_R3_R1_0 ## r3 = cursor + P1_LI_R0 + '00000000' + P1_SB_R0_R3_0 + P1_ADDI_R3_R3_1 + P1_ST_R3_R1_0 + + ## argv_out[token_count] = start; token_count++. + P1_LI_R1 + &token_count + P1_LD_R3_R1_0 ## r3 = count + P1_SHLI_R0_R3_3 ## r0 = count*8 + P1_LI_R1 + &argv_out + P1_ADD_R1_R1_R0 ## r1 = &argv_out[count] + P1_ST_R2_R1_0 ## store start ptr + + P1_LI_R1 + &token_count + P1_LD_R3_R1_0 + P1_ADDI_R3_R3_1 + P1_ST_R3_R1_0 ## count++ + + ## current_token_ptr = 0. + P1_LI_R1 + &current_token_ptr + P1_LI_R2 + '00000000' + P1_ST_R2_R1_0 + +:end_token_none + P1_RET + + +## ---- collect_token() — read a plain word into the arena ---------- +## Called when the peek-char is a non-space, non-special, non-quote +## byte. Consumes chars until a separator/newline/EOF/#/"/\\ and +## leaves the token open (caller invokes end_token at the dispatch). +:collect_token + P1_PROLOGUE +:collect_token_loop + P1_LI_BR + &peek_char + P1_CALL ## r0 = c + + ## EOF → end of token. + P1_LI_R1 + '00000000' + P1_ADDI_R1_R1_NEG1 + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + ## '\n' + P1_LI_R1 + '0A000000' + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + ## ' ' + P1_LI_R1 + '20000000' + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + ## '\t' + P1_LI_R1 + '09000000' + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + ## '#' — comment starts mid-token too (kaem-minimal semantics). + P1_LI_R1 + '23000000' + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + ## '"' — string terminates plain token. + P1_LI_R1 + '22000000' + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + ## '\\' — also terminates plain token (collect_command handles the + ## skip+drop outside). + P1_LI_R1 + '5C000000' + P1_LI_BR + &collect_token_done + P1_BEQ_R0_R1 + + ## Otherwise: copy into arena, consume, continue. + P1_MOV_R1_R0 + P1_LI_BR + &arena_putc + P1_CALL + P1_LI_BR + &advance_char + P1_CALL + P1_LI_BR + &collect_token_loop + P1_B + +:collect_token_done + P1_EPILOGUE + P1_RET + + +## ---- collect_string() — read a "..." raw literal ----------------- +## Enters with the opening '"' still under peek. Consumes it, then +## copies bytes verbatim into the arena until the closing '"'. The +## closing quote is consumed. Leaves the token open. +:collect_string + P1_PROLOGUE + ## eat opening '"'. + P1_LI_BR + &advance_char + P1_CALL + + ## Ensure the token is opened even for empty strings "" — call + ## arena_putc with 0 bytes wouldn't open. Force-open by writing + ## then rolling back: simpler path is a direct "open if closed" + ## flag, but arena_putc already opens on first call. For empty + ## strings we rely on end_token() to skip if no token is open + ## (kaem-minimal behavior: empty "" emits no token). + +:collect_string_loop + P1_LI_BR + &peek_char + P1_CALL + ## EOF mid-string: match kaem-minimal by just stopping (it would + ## abort; for our Makefile use this is benign). + P1_LI_R1 + '00000000' + P1_ADDI_R1_R1_NEG1 + P1_LI_BR + &collect_string_done + P1_BEQ_R0_R1 + ## closing '"' + P1_LI_R1 + '22000000' + P1_LI_BR + &collect_string_close + P1_BEQ_R0_R1 + + ## Any other byte: copy literally. + P1_MOV_R1_R0 + P1_LI_BR + &arena_putc + P1_CALL + P1_LI_BR + &advance_char + P1_CALL + P1_LI_BR + &collect_string_loop + P1_B + +:collect_string_close + P1_LI_BR + &advance_char + P1_CALL ## eat closing '"' +:collect_string_done + P1_EPILOGUE + P1_RET + + +## ---- collect_comment() — skip '#' through end of line ------------ +## Called with the '#' under peek. Consumes '#' and everything up to +## but NOT including '\n' (so collect_command's outer loop sees '\n' +## and terminates the command). +:collect_comment + P1_PROLOGUE + P1_LI_BR + &advance_char + P1_CALL ## eat '#' +:collect_comment_loop + P1_LI_BR + &peek_char + P1_CALL + P1_LI_R1 + '00000000' + P1_ADDI_R1_R1_NEG1 + P1_LI_BR + &collect_comment_done + P1_BEQ_R0_R1 ## EOF → done + P1_LI_R1 + '0A000000' + P1_LI_BR + &collect_comment_done + P1_BEQ_R0_R1 ## '\n' → leave it + P1_LI_BR + &advance_char + P1_CALL + P1_LI_BR + &collect_comment_loop + P1_B +:collect_comment_done + P1_EPILOGUE + P1_RET + + +## ---- collect_command() — tokenize one logical line -------------- +## Top of collect_command: +## - separator ' ' or '\t' → end_token, advance, continue +## - '\n' → end_token, advance, return +## - EOF → end_token, return +## - '#' → end_token, collect_comment, continue (next iter hits \n) +## - '"' → collect_string (keeps token open across quotes) +## - '\\' → advance twice (drop \\ and next char), end_token, continue +## - else → collect_token (grows token) +:collect_command + P1_PROLOGUE +:collect_command_loop + P1_LI_BR + &peek_char + P1_CALL ## r0 = c + + ## EOF → close any open token and return. + P1_LI_R1 + '00000000' + P1_ADDI_R1_R1_NEG1 + P1_LI_BR + &collect_command_done + P1_BEQ_R0_R1 + ## '\n' + P1_LI_R1 + '0A000000' + P1_LI_BR + &collect_command_eat_nl + P1_BEQ_R0_R1 + ## ' ' + P1_LI_R1 + '20000000' + P1_LI_BR + &collect_command_sep + P1_BEQ_R0_R1 + ## '\t' + P1_LI_R1 + '09000000' + P1_LI_BR + &collect_command_sep + P1_BEQ_R0_R1 + ## '#' + P1_LI_R1 + '23000000' + P1_LI_BR + &collect_command_comment + P1_BEQ_R0_R1 + ## '"' + P1_LI_R1 + '22000000' + P1_LI_BR + &collect_command_str + P1_BEQ_R0_R1 + ## '\\' + P1_LI_R1 + '5C000000' + P1_LI_BR + &collect_command_bslash + P1_BEQ_R0_R1 + + ## Plain char — start/continue a token. + P1_LI_BR + &collect_token + P1_CALL + P1_LI_BR + &collect_command_loop + P1_B + +:collect_command_sep + P1_LI_BR + &end_token + P1_CALL + P1_LI_BR + &advance_char + P1_CALL + P1_LI_BR + &collect_command_loop + P1_B + +:collect_command_comment + P1_LI_BR + &end_token + P1_CALL + P1_LI_BR + &collect_comment + P1_CALL + P1_LI_BR + &collect_command_loop + P1_B + +:collect_command_str + P1_LI_BR + &collect_string + P1_CALL + P1_LI_BR + &collect_command_loop + P1_B + +:collect_command_bslash + ## Drop the backslash, then drop the next char (if any), then end + ## the token. Two advance_chars + end_token, per kaem-minimal.c. + P1_LI_BR + &advance_char + P1_CALL + P1_LI_BR + &peek_char + P1_CALL + P1_LI_R1 + '00000000' + P1_ADDI_R1_R1_NEG1 + P1_LI_BR + &collect_command_bslash_end + P1_BEQ_R0_R1 + P1_LI_BR + &advance_char + P1_CALL +:collect_command_bslash_end + P1_LI_BR + &end_token + P1_CALL + P1_LI_BR + &collect_command_loop + P1_B + +:collect_command_eat_nl + P1_LI_BR + &end_token + P1_CALL + P1_LI_BR + &advance_char + P1_CALL + +:collect_command_done + P1_LI_BR + &end_token + P1_CALL + P1_EPILOGUE + P1_RET + + +## ---- strlen(r1 = cstr) -> r0 = length --------------------------- +:strlen + P1_LI_R0 + '00000000' +:strlen_loop + P1_ADD_R2_R0_R1 + P1_LB_R3_R2_0 + P1_LI_R2 + '00000000' + P1_LI_BR + &strlen_done + P1_BEQ_R3_R2 + P1_ADDI_R0_R0_1 + P1_LI_BR + &strlen_loop + P1_B +:strlen_done + P1_RET + + +## ---- write_cstr(r1 = cstr, r2 = fd) ----------------------------- +## strlen + one SYS_WRITE. Uses r4 to carry fd, r5 to carry ptr across +## the strlen CALL (r4/r5 are callee-saved, preserved by strlen). +:write_cstr + P1_PROLOGUE + P1_MOV_R4_R2 ## r4 = fd + P1_MOV_R5_R1 ## r5 = cstr + P1_LI_BR + &strlen + P1_CALL ## r0 = len + + P1_MOV_R3_R0 ## r3 = count + P1_MOV_R2_R5 ## r2 = buf + P1_MOV_R1_R4 ## r1 = fd + P1_LI_R0 + SYS_WRITE + P1_SYSCALL + P1_EPILOGUE + P1_RET + + +## ---- emit_verbose() — print " +> tok1 tok2 ... tokN\n" to fd 1 - +## Walks argv_out[0..token_count-1], emitting each token preceded by +## a separator (" +> " before the first, " " before the rest), then +## a trailing newline. +:emit_verbose + P1_PROLOGUE_N2 + ## slot1 = i (loop index). slot2 = fd const (not strictly needed + ## but cheap to keep). + P1_MOV_R3_SP + P1_LI_R1 + '00000000' + P1_ST_R1_R3_8 ## i = 0 + + ## " +> " prefix. + P1_LI_R0 + SYS_WRITE + P1_LI_R1 + '01000000' + P1_LI_R2 + &msg_verbose_prefix + P1_LI_R3 + '04000000' + P1_SYSCALL + +:emit_verbose_loop + P1_MOV_R3_SP + P1_LD_R1_R3_8 ## r1 = i + P1_LI_R2 + &token_count + P1_LD_R2_R2_0 + P1_LI_BR + &emit_verbose_done + P1_BEQ_R1_R2 ## i == count → done + + ## If i > 0, write a separating space. + P1_LI_R2 + '00000000' + P1_LI_BR + &emit_verbose_skip_space + P1_BEQ_R1_R2 + P1_LI_R0 + SYS_WRITE + P1_LI_R1 + '01000000' + P1_LI_R2 + &msg_space + P1_LI_R3 + '01000000' + P1_SYSCALL + +:emit_verbose_skip_space + ## Write argv_out[i] as a C string. + P1_MOV_R3_SP + P1_LD_R1_R3_8 ## r1 = i + P1_SHLI_R1_R1_3 ## r1 = i*8 + P1_LI_R2 + &argv_out + P1_ADD_R1_R1_R2 + P1_LD_R1_R1_0 ## r1 = argv_out[i] + P1_LI_R2 + '01000000' ## fd = 1 + P1_LI_BR + &write_cstr + P1_CALL + + P1_MOV_R3_SP + P1_LD_R1_R3_8 + P1_ADDI_R1_R1_1 + P1_ST_R1_R3_8 ## i++ + P1_LI_BR + &emit_verbose_loop + P1_B + +:emit_verbose_done + ## Trailing newline. + P1_LI_R0 + SYS_WRITE + P1_LI_R1 + '01000000' + P1_LI_R2 + &msg_newline + P1_LI_R3 + '01000000' + P1_SYSCALL + P1_EPILOGUE_N2 + P1_RET + + +## ---- spawn_and_wait() — clone + execve + waitid --------------- +## Builds a NULL-terminated argv in argv_out (the token pointers are +## already there; just stamp a NULL past the last one). Then: +## pid = clone(SIGCHLD, 0, 0, 0, 0) +## if pid == 0: +## execve(argv_out[0], argv_out, envp); _exit(127) +## else: +## waitid(P_PID, pid, &siginfo_buf, WEXITED, 0) +## if siginfo_buf.si_status byte != 0 → die +## Uses waitid rather than wait4 because wait4 is not in the generic +## Linux syscall table that aarch64/riscv64 share (aarch64 #260 is +## 32-bit-compat only). waitid is uniform: amd64=247, aarch64=95, +## riscv64=95. +:spawn_and_wait + P1_PROLOGUE + + ## Stamp NULL into argv_out[token_count]. + P1_LI_R1 + &token_count + P1_LD_R1_R1_0 + P1_SHLI_R1_R1_3 + P1_LI_R2 + &argv_out + P1_ADD_R1_R1_R2 ## r1 = &argv_out[count] + P1_LI_R2 + '00000000' + P1_ST_R2_R1_0 + + ## clone(flags=SIGCHLD=17, stack=0, ptid=0, ctid=0, tls=0) + ## Arg order past arg3 differs slightly across arches (aarch64/ + ## riscv64 swap tls and ctid relative to amd64) but all args >= 4 + ## are 0 here so the divergence is benign. + P1_LI_R0 + SYS_CLONE + P1_LI_R1 + '11000000' ## SIGCHLD = 17 + P1_LI_R2 + '00000000' + P1_LI_R3 + '00000000' + P1_LI_R4 + '00000000' + P1_LI_R5 + '00000000' + P1_LI_R6 + '00000000' + P1_SYSCALL ## r0 = pid (parent) or 0 (child) + + ## Child? + P1_LI_R1 + '00000000' + P1_LI_BR + &spawn_child + P1_BEQ_R0_R1 + + ## Parent: waitid(P_PID=1, pid, &siginfo_buf, WEXITED=4, rusage=0). + ## Move pid into r2 before we clobber r0 with the syscall number. + P1_MOV_R2_R0 ## r2 = id = pid + P1_LI_R0 + SYS_WAITID + P1_LI_R1 + '01000000' ## idtype = P_PID = 1 + P1_LI_R3 + &siginfo_buf ## siginfo_t out + P1_LI_R4 + '04000000' ## options = WEXITED = 4 + P1_LI_R5 + '00000000' ## rusage = NULL + P1_SYSCALL + + ## Check si_status (32-bit int at siginfo_buf+24). For CLD_EXITED + ## it holds the exit code; for CLD_KILLED it holds the signal + ## number. Either way we only pass if every byte is 0, and exit + ## codes / signal numbers are < 256 so the low byte is sufficient. + P1_LI_R1 + &siginfo_buf + P1_LB_R1_R1_24 + P1_LI_R2 + '00000000' + P1_LI_BR + &spawn_ok + P1_BEQ_R1_R2 + + ## Print abort message to stderr, exit 1. + P1_LI_R0 + SYS_WRITE + P1_LI_R1 + '02000000' + P1_LI_R2 + &msg_abort + P1_LI_R3 + &msg_abort_end + P1_SUB_R3_R3_R2 + P1_SYSCALL + P1_LI_R0 + SYS_EXIT + P1_LI_R1 + '01000000' + P1_SYSCALL + +:spawn_ok + P1_EPILOGUE + P1_RET + +:spawn_child + ## execve(argv_out[0], argv_out, envp) + P1_LI_R1 + &argv_out + P1_LD_R1_R1_0 ## r1 = filename = argv_out[0] + P1_LI_R2 + &argv_out ## r2 = argv + P1_LI_R3 + &envp_ptr + P1_LD_R3_R3_0 ## r3 = envp + P1_LI_R0 + SYS_EXECVE + P1_SYSCALL + + ## execve returned → failure. exit(127) so the parent's wait4 + ## sees a non-zero status and aborts. + P1_LI_R0 + SYS_EXIT + P1_LI_R1 + '7F000000' + P1_SYSCALL + + +## ==================================================================== +## Constant pool + mutable globals + zero-filled arenas. +## All live in the single PT_LOAD segment (flags=7 RWX), so the arenas +## are writable in place. +## ==================================================================== + +## ---- Constant strings ----------------------------------------------- +:default_filename +"kaem.run" +'00' + +:msg_verbose_prefix +" +> " + +:msg_space +" " + +:msg_newline +" +" + +:msg_openfail +"kaem: cannot open script +" +:msg_openfail_end + +:msg_abort +"Subprocess error +ABORTING HARD +" +:msg_abort_end + + +## ---- Mutable globals (8 bytes each, 8-aligned so LD/ST work) ------- +## Listed after strings so they're likely 8-aligned; if not, the code +## still accesses them via 8-byte LD/ST which is aligned on amd64 and +## requires 8-alignment on aarch64/riscv64. See P1.md §"Data alignment". +## (Per-arch layout is deterministic but not identical; if this trips +## a #SIGBUS on aarch64, insert a single-byte padding label above.) +:globals_pad +'00' +'00' +'00' +'00' +'00' +'00' +'00' + +:script_fd +'0000000000000000' + +:envp_ptr +'0000000000000000' + +:src_pos +'0000000000000000' + +:src_len +'0000000000000000' + +:token_count +'0000000000000000' + +:token_arena_next +'0000000000000000' + +:current_token_ptr +'0000000000000000' + +## siginfo_t output buffer for waitid — 128 bytes. si_status (the +## exit code / signal number) lives at offset 24. +:siginfo_buf +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +:siginfo_buf_end + + +## ---- argv_out — NULL-terminated C argv for execve ---------------- +## 128 slots × 8 = 1024 bytes. Enough headroom for any realistic +## command in a build script; kaem.run lines rarely exceed a dozen. +:argv_out +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +:argv_out_end + + +## ---- token_arena — byte pool for token text -------------------- +## 4096 bytes: far more than any shell line we're likely to emit. +## Reset on every command; never spills across commands. +:token_arena +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +:token_arena_end + + +## ---- read_buf — file slurp buffer ------------------------------- +## 16 KiB covers any reasonable build script. At 128 bytes per line +## this is 128 lines × 32 hex chars. +:read_buf +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +:read_buf_end + +:ELF_end + diff --git a/kaem.run b/kaem.run @@ -0,0 +1,3 @@ +/bin/echo hello +/bin/echo "world" +/bin/true diff --git a/p1_gen.py b/p1_gen.py @@ -765,10 +765,10 @@ class Ret(Op): return enc.ret() -## ---------- SYSCALL / SYSOPEN pre-encoded sequences --------------------- -## These are the one-shot syscall wrappers. They shuffle P1's r0=num, -## r1–r6=args convention into each arch's native syscall ABI and clobber -## only r0 on return. Encoded by hand (per P1.md §"Syscall conventions"). +## ---------- SYSCALL pre-encoded sequences ------------------------------- +## The one-shot syscall wrapper. Shuffles P1's r0=num, r1–r6=args into +## each arch's native syscall ABI and clobbers only r0 on return. +## Encoded by hand (per P1.md §"Syscall conventions"). SYSCALL_HEX = { 'aarch64': ( @@ -819,26 +819,28 @@ SYSCALL_HEX = { ), } -SYSOPEN_HEX = { - # aarch64: movn x0,#99 ; movz x8,#56 ; svc #0 - 'aarch64': le32(0x92800C60) + le32(0xD2800708) + le32(0xD4000001), - # amd64: mov eax,2 (open) ; syscall - 'amd64': 'B8' + le32(2) + '0F05', - # riscv64: addi a0,zero,-100 ; addi a7,zero,56 ; ecall - 'riscv64': le32(0xF9C00513) + le32(0x03800893) + le32(0x00000073), -} - ## Syscall numbers (little-endian 32-bit for LI operand). -## aarch64 and riscv64 share the asm-generic table (write=64, exit=93, -## clone=220, execve=221, waitid=95). amd64 has its own arch-specific -## numbers. `wait4` is deliberately absent — it's only defined for -## 32-bit compat on aarch64/riscv64; `waitid` is the portable choice. +## aarch64 and riscv64 share the asm-generic table; amd64 has its own. +## +## Portability notes — every entry below is a syscall that exists on all +## three with the same semantics under the uniform P1 SYSCALL convention +## (r0 = num, r1-r6 = args): +## - `fork` is amd64-only; `wait4` is asm-generic 32-bit compat only. +## Use `clone(SIGCHLD)` and `waitid` instead. +## - `open` is amd64-only (removed from asm-generic). Use `openat` with +## dirfd = AT_FDCWD (-100) as arg1. +## - `clone` arg order differs: amd64 is (flags, stack, ptid, ctid, tls); +## aarch64/riscv64 are (flags, stack, ptid, tls, ctid). Benign when +## ptid/ctid/tls are all zero (the fork-equivalent case). SYS_NUM = { - 'aarch64': {'SYS_WRITE': 64, 'SYS_EXIT': 93, 'SYS_READ': 63, 'SYS_CLOSE': 57, + 'aarch64': {'SYS_WRITE': 64, 'SYS_EXIT': 93, 'SYS_READ': 63, 'SYS_CLOSE': 57, + 'SYS_OPENAT': 56, 'SYS_CLONE': 220, 'SYS_EXECVE': 221, 'SYS_WAITID': 95}, - 'amd64': {'SYS_WRITE': 1, 'SYS_EXIT': 60, 'SYS_READ': 0, 'SYS_CLOSE': 3, - 'SYS_CLONE': 56, 'SYS_EXECVE': 59, 'SYS_WAITID': 247}, - 'riscv64': {'SYS_WRITE': 64, 'SYS_EXIT': 93, 'SYS_READ': 63, 'SYS_CLOSE': 57, + 'amd64': {'SYS_WRITE': 1, 'SYS_EXIT': 60, 'SYS_READ': 0, 'SYS_CLOSE': 3, + 'SYS_OPENAT':257, + 'SYS_CLONE': 56, 'SYS_EXECVE': 59, 'SYS_WAITID':247}, + 'riscv64': {'SYS_WRITE': 64, 'SYS_EXIT': 93, 'SYS_READ': 63, 'SYS_CLOSE': 57, + 'SYS_OPENAT': 56, 'SYS_CLONE': 220, 'SYS_EXECVE': 221, 'SYS_WAITID': 95}, } @@ -1003,14 +1005,13 @@ def rows(): R.append(Epilogue(name=f'EPILOGUE_N{k}', k=k)) R.append(Tail(name=f'TAIL_N{k}', k=k)) - # --- SYSCALL / SYSOPEN — pre-encoded per-arch wrappers --- - R.append(Banner('SYSCALL / SYSOPEN — uniform "clobbers r0 only" across arches')) + # --- SYSCALL — pre-encoded per-arch wrapper --- + R.append(Banner('SYSCALL — uniform "clobbers r0 only" across arches')) R.append(Literal(name='SYSCALL', hex_by_arch=SYSCALL_HEX)) - R.append(Literal(name='SYSOPEN', hex_by_arch=SYSOPEN_HEX)) # --- Syscall numbers (LE-32 immediates) --- R.append(Banner('Linux syscall numbers (per-arch table). LE-32 operands for LI.')) - for name in ('SYS_WRITE', 'SYS_EXIT', 'SYS_READ', 'SYS_CLOSE', + for name in ('SYS_WRITE', 'SYS_EXIT', 'SYS_READ', 'SYS_CLOSE', 'SYS_OPENAT', 'SYS_CLONE', 'SYS_EXECVE', 'SYS_WAITID'): R.append(Literal(name=name, hex_by_arch={a: le32(SYS_NUM[a][name]) for a in ARCHES}))