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:
| A | kaem-minimal.M1 | | | 1313 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | kaem.run | | | 3 | +++ |
| M | p1_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
+ ¤t_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
+ ¤t_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
+ ¤t_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
+ ¤t_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}))