boot2

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

commit ebb6ead5854a278ec3e5f5c72a7a536a114e67d5
parent 877607adbf647dd1bf3942699d4efcef757571e4
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun,  3 May 2026 20:53:41 -0700

libp1pp: namespace mem* / str* helpers under libp1pp__

Rename libp1pp's freestanding string and byte primitives:
:memcpy → :libp1pp__memcpy, :memset → :libp1pp__memset,
:memcmp → :libp1pp__memcmp, :strlen → :libp1pp__strlen,
:streq → :libp1pp__streq, :strcmp → :libp1pp__strcmp.

Without the prefix, libp1pp's public entry points collide with libc's
own `:memcpy` / `:memcmp` / `:memset` once a translation unit links
against the mes-libc chain (cc-libc, tcc-boot2). hex2++ rejects the
duplicate global label, so the entire combined libc + tcc.flat
target failed to assemble. The prefix gives libp1pp's helpers their
own namespace; libc's libc-named entry points keep ownership of the
public C names.

Update %memcpy_call (the macro cc.scm's struct copies and scheme1's
heap copies route through) and scheme1.P1pp's direct callsites to
the prefixed names. tests/cc/129-extern-libp1pp.c — the regression
that pins cc.scm's bare-name extern passthrough — moves to the
prefixed extern decls so plain `tests/cc` fixtures can still link
against libp1pp without dragging libc in.

docs/LIBP1PP.md still documents these as bare unprefixed names; that
doc needs a follow-up update.

Diffstat:
MP1/P1pp.P1pp | 35+++++++++++++++++++----------------
Mscheme1/scheme1.P1pp | 20++++++++++----------
Mtests/cc/129-extern-libp1pp.c | 33+++++++++++++++++----------------
3 files changed, 46 insertions(+), 42 deletions(-)

diff --git a/P1/P1pp.P1pp b/P1/P1pp.P1pp @@ -289,7 +289,7 @@ %li(a2, n_imm) %mov(a1, src_reg) %mov(a0, dst_reg) - %call(&memcpy) + %call(&libp1pp__memcpy) %endm # ========================================================================= @@ -890,10 +890,13 @@ # Memory and strings # ========================================================================= -# memcpy(dst=a0, src=a1, n=a2) -> dst (a0) +# libp1pp__memcpy(dst=a0, src=a1, n=a2) -> dst (a0) # Leaf. Copies n bytes from src to dst. No overlap support where -# dst > src && dst < src + n. -:memcpy +# dst > src && dst < src + n. Internal name so a libc that defines its +# own :memcpy can be linked alongside libp1pp without duplicate-label +# errors at hex2++ time. cc.scm's %memcpy_call macro and scheme1 +# bind this prefixed name directly. +:libp1pp__memcpy .scope %mov(a3, a0) %li(t0, 0) @@ -910,8 +913,8 @@ %ret .endscope -# memset(dst=a0, byte=a1, n=a2) -> dst (a0) -:memset +# libp1pp__memset(dst=a0, byte=a1, n=a2) -> dst (a0) +:libp1pp__memset .scope %mov(a3, a0) %li(t0, 0) @@ -926,8 +929,8 @@ %ret .endscope -# memcmp(a=a0, b=a1, n=a2) -> -1/0/1 (a0) -:memcmp +# libp1pp__memcmp(a=a0, b=a1, n=a2) -> -1/0/1 (a0) +:libp1pp__memcmp .scope %li(t0, 0) :.loop @@ -951,8 +954,8 @@ %ret .endscope -# strlen(cstr=a0) -> n (a0) -:strlen +# libp1pp__strlen(cstr=a0) -> n (a0) +:libp1pp__strlen .scope %mov(a1, a0) :.loop @@ -965,8 +968,8 @@ %ret .endscope -# streq(a=a0, b=a1) -> 0 or 1 -:streq +# libp1pp__streq(a=a0, b=a1) -> 0 or 1 +:libp1pp__streq .scope :.loop %lb(t0, a0, 0) @@ -984,8 +987,8 @@ %ret .endscope -# strcmp(a=a0, b=a1) -> -1/0/1 -:strcmp +# libp1pp__strcmp(a=a0, b=a1) -> -1/0/1 +:libp1pp__strcmp .scope :.loop %lb(t0, a0, 0) @@ -1470,7 +1473,7 @@ %fn(print_cstr, 16, { %st(s0, sp, 0) %mov(s0, a0) - %call(&strlen) + %call(&libp1pp__strlen) %mov(a1, a0) %mov(a0, s0) %call(&print) @@ -1480,7 +1483,7 @@ %fn(eprint_cstr, 16, { %st(s0, sp, 0) %mov(s0, a0) - %call(&strlen) + %call(&libp1pp__strlen) %mov(a1, a0) %mov(a0, s0) %call(&eprint) diff --git a/scheme1/scheme1.P1pp b/scheme1/scheme1.P1pp @@ -881,7 +881,7 @@ %mov(a0, t2) %la(a1, name_label) %li(a2, len) - %call(&memcmp) + %call(&libp1pp__memcmp) %bnez(a0, &.bad) %li(a0, value) %mkfix(a0, a0) @@ -2989,7 +2989,7 @@ %ld(a0, t1, %SYMENT.name_ptr) %ldl(a1, name_ptr) %ldl(a2, name_len) - %call(&memcmp) + %call(&libp1pp__memcmp) %beqz(a0, &.found) :.next @@ -3014,7 +3014,7 @@ %call(&alloc_bytes_main) %ldl(a1, name_ptr) %ldl(a2, name_len) - %call(&memcpy) ; returns dst in a0 = stable copy + %call(&libp1pp__memcpy) ; returns dst in a0 = stable copy %ldl(t0, idx) %symtab_entry(t1, t0, t2) @@ -3390,7 +3390,7 @@ %cdr(t0, t0) %stl(t0, args) - %call(&memcpy) + %call(&libp1pp__memcpy) %b(&.copy_loop) :.copy_done @@ -3425,7 +3425,7 @@ %ldl(a2, len) ; len %heap_ld(t0, a0, %BV.data) ; dst = bv.data %mov(a0, t0) - %call(&memcpy) + %call(&libp1pp__memcpy) %ldl(a0, bv) }) @@ -3985,7 +3985,7 @@ %ldl(a0, new_data_ptr) %heap_ld(a1, t0, %BV.data) ; old data ptr %ldl(a2, raw) - %call(&memcpy) + %call(&libp1pp__memcpy) %ldl(t0, bv) %ldl(t1, new_data_ptr) @@ -4051,7 +4051,7 @@ %fn(prim_string_length_entry, 0, { %car(t0, a0) %heap_ld(a0, t0, %BV.data) - %call(&strlen) + %call(&libp1pp__strlen) %mkfix(a0, a0) %eret }) @@ -4812,7 +4812,7 @@ %add(a0, a0, t1) ; dst = data + old_len %ldl(a1, src) %ldl(a2, n) - %call(&memcpy) + %call(&libp1pp__memcpy) # hdr = (old_len + n) << 8 | HDR.BV. HDR.BV is 0. %ldl(t0, old_len) @@ -5716,7 +5716,7 @@ # len = strlen(*argv) %ldl(t0, argv) %ld(a0, t0, 0) - %call(&strlen) + %call(&libp1pp__strlen) # bv = str_alloc(len). argv entries flow into syscalls (sys-openat, # sys-execve) that read data_ptr as a C string, so the trailing NUL @@ -5731,7 +5731,7 @@ %ld(a1, t1, 0) %heap_ld(t1, t0, %BV.hdr) %shri(a2, t1, 8) - %call(&memcpy) + %call(&libp1pp__memcpy) # cell = cons(bv, NIL); append to list head/tail. %ldl(a0, bv) diff --git a/tests/cc/129-extern-libp1pp.c b/tests/cc/129-extern-libp1pp.c @@ -1,22 +1,23 @@ /* Calls into libp1pp routines via plain C `extern` declarations. The - * libp1pp side already provides `:memcpy`, `:memcmp`, and `:memset` - * as bare-name labels (see P1/P1pp.P1pp). For these to link, - * cc.scm must NOT prefix `extern`-but-not-defined-here symbols with - * its `cc__` namespace — bare-name extern decls should pass through. + * libp1pp side provides `:libp1pp__memcpy`, `:libp1pp__memcmp`, and + * `:libp1pp__memset` as bare-name labels (see P1/P1pp.P1pp). For these + * to link, cc.scm must NOT prefix `extern`-but-not-defined-here symbols + * with its `cc__` namespace — bare-name extern decls should pass through. * - * This is the linkage rule that lets the tcc-boot2 path resolve all - * the low-level memory symbols (memcpy/memcmp/memset/etc.) tcc.c calls. - * Do not test stdio/libc string APIs here; plain tests/cc fixtures should - * stay freestanding. + * The `libp1pp__` prefix keeps these freestanding helpers from clashing + * with libc's own `:memcpy` / `:memcmp` / `:memset` when a translation + * unit is linked against the mes-libc chain (cc-libc / tcc-boot2). + * Plain tests/cc fixtures stay freestanding and bind the prefixed names + * directly. Do not test stdio/libc string APIs here. */ -extern void *memcpy(void *, const void *, unsigned long); -extern int memcmp(const void *, const void *, unsigned long); -extern void *memset(void *, int, unsigned long); +extern void *libp1pp__memcpy(void *, const void *, unsigned long); +extern int libp1pp__memcmp(const void *, const void *, unsigned long); +extern void *libp1pp__memset(void *, int, unsigned long); int test_memcpy(void) { char buf[8]; - memcpy(buf, "abcdefg", 8); + libp1pp__memcpy(buf, "abcdefg", 8); if (buf[0] != 'a') return 1; if (buf[3] != 'd') return 2; if (buf[6] != 'g') return 3; @@ -25,15 +26,15 @@ int test_memcpy(void) { } int test_memcmp(void) { - if (memcmp("hello", "hello", 5) != 0) return 1; - if (memcmp("hello", "help!", 5) == 0) return 2; - if (memcmp("a", "b", 1) == 0) return 3; + if (libp1pp__memcmp("hello", "hello", 5) != 0) return 1; + if (libp1pp__memcmp("hello", "help!", 5) == 0) return 2; + if (libp1pp__memcmp("a", "b", 1) == 0) return 3; return 0; } int test_memset(void) { char buf[6]; - memset(buf, 'X', 5); + libp1pp__memset(buf, 'X', 5); buf[5] = 0; if (buf[0] != 'X') return 1; if (buf[2] != 'X') return 2;