C stdio must ride pxx syscalls (libc-free), not import libc
- Type: library work (Track C — lib/crtl, C frontend builtins). NOT Track A.
- Status: done
- Found: 2026-06-26 getting pxx-compiled lua to RUN. Reframed after review: pxx does stdio via direct SYSCALLS (like Pascal), never libc. File/console IO must STAY libc-free. (Earlier "import libc stdout via COPY relocation" framing was WRONG — discard it.)
- Closed: 2026-06-27
Original State
printfalready works: the C frontend intercepts the name ->AN_WRITE(a write syscall, cparser.inc ~1230). No libc.fwrite/fputs/fputc/puts/stdout/stderr/stdindo NOT bridge — they fall through to the default libc.so.6 import.stdoutis a libc DATA symbol pxx doesn't import, so it reads 0 and lua'slua_writestring(fwrite(s,1,n,stdout)) null-derefs. lua RUNS non-IO code; any output crashes.- C cannot emit a raw syscall (
__asm__unsupported), so the bridge must be a pxx intrinsic or a Pascal-backed helper.
Fix — REUSE the existing Pascal RTL (do NOT rewrite IO)
KEY: C can import Pascal libraries, and the Pascal RTL already implements file/console IO once, PAL-aware (posix syscalls / ESP-IDF). So C stdio is a thin C-ABI VENEER that calls the EXISTING Pascal RTL IO routines — not a new __pxx_write + a from-scratch stdio.c. No duplication, no second IO path.
- stdout/stderr/stdin -> map to the Pascal RTL's standard handles / fd 1,2,0.
- fwrite/fputs/fputc/puts/fread/fopen/fclose/fseek/fflush -> call the matching
Pascal RTL routine (the one Pascal
write/Assign/BlockWrite/file API already uses), which already dispatches through the PAL (posix vs ESP-IDF). - The earlier "__pxx_write builtin + lib/crtl/src/stdio.c from scratch" plan is superseded by this: only write the veneer + the C<->Pascal RTL binding. printf staying on AN_WRITE is fine, or also re-point it at the RTL for consistency.
(superseded) earlier from-scratch sketch
- Add a low-level syscall bridge usable from C: a
__pxx_write(int fd, const void *buf, unsigned long len)builtin that emits the write syscall (reuse the AN_WRITE / AN_SYSCALL path the printf stub already uses). Likewise__pxx_readfor input. ESP/cross go through the PAL, same as Pascal. - lib/crtl/src/stdio.c: define
FILEsostdout/stderr/stdinare real objects carrying fd 1/2/0; implementfwrite/fputs/fputc/putchar/puts/fflush/fread/fopen/fclose/fseekon__pxx_write/__pxx_read- the open/close/lseek syscalls. Compile it into the program (amalgamation), so these resolve INTERNALLY — no libc.so.6 import for IO.
- Abstraction (IMPORTANT): C stdio is a thin C-ABI veneer over the PAL, NOT a
fork and NOT hardcoded syscalls. The PAL backend decides the mechanism:
- posix (x86-64/linux): raw write/read/open/lseek syscalls.
- ESP32: route through ESP-IDF (assume IDF for now; IDF provides vfs/console/fatfs). stdio without IDF is possible but out of scope. So _pxx_write etc. dispatch to the active PAL (PXX_PLATFORM*), exactly like Pascal's IO already does — C and Pascal share ONE platform IO layer.
Resolution
- 2026-06-27 audit — DONE / no longer reproducible. Solved by the later
pxxcioPAL bridge and C stdio work. Currentcompiler/pascal26builds and runstest/cfile_stdio_b87.candtest/csocket_loopback_b88.c; both return42.readelf -don those binaries reports noNEEDED libc.so.6entry. - The pinned Track B compiler still lags this behavior; that is tracked
separately by
chore-repin-c-stdio-pal-bridge.