commit c6a82a3a2bc1166329ee461d9c9d152ee5709ea6
parent 3d4a605868477322720da30bfb1ce9e6abbcecb1
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 29 Apr 2026 23:22:47 -0700
entry-libc: save argc/argv across __libc_init
__libc_init may return through a0; if the callee-saved path through the
P1 ABI doesn't preserve a0/a1 across the call, main receives garbage
arguments. Allocate a 16-byte frame in p1_main and spill/reload argc
(a0) and argv (a1) around the __libc_init call.
Diffstat:
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/P1/entry-libc.P1pp b/P1/entry-libc.P1pp
@@ -5,15 +5,19 @@
# main. __libc_init (boot2-syscall.c) reads argv's NULL terminator
# to populate `environ` so getenv()/etc don't dereference a NULL
# environment pointer on the first call. argc/argv arrive in a0/a1
-# from the bootstrap _start; %call doesn't clobber them, so the
-# second %call delivers them to main unchanged.
+# from the bootstrap _start; save them across __libc_init so main sees
+# the original process arguments even if libc init returns through a0.
#
# Cat this in exactly once at the head of a libc-using catm chain
# and pair with P1/elf-end.P1pp at the tail. Library TUs (libc,
# client) should be built with cc.scm --lib=PFX so they don't
# also try to define :p1_main.
-%fn(p1_main, 0, {
+%fn(p1_main, 16, {
+ %st(a0, sp, 0)
+ %st(a1, sp, 8)
%call(&__libc_init)
+ %ld(a0, sp, 0)
+ %ld(a1, sp, 8)
%call(&main)
})