6l: port ET_DYN dynamic linking to the ww side

Ports cmd/6l/{dyn,dynout}.c into selfhost/cmd/6l/{dyn,dynout}.ww:
ET_DYN .so loading + PT_INTERP/PT_DYNAMIC ELF emission with .rela.plt,
.gnu.version_r, BIND_NOW. lsym grows dyn fields; pass.ww promotes
undefs to dyn; out.ww dispatches; main.ww takes -L/-l. The ww driver
forwards -L/-l to 6l_ww so 'ww_ww build snake.ww -L /usr/lib -l ncurses
-l c' runs without cc.

Test 996 pins byte-identical output to C-6l on snake.

'make bootstrap' gains a fourth stage with cmp ww3 == ww4, proving
ww3 is byte-stable when used as a compiler — not just a coincidental
two-stage equilibrium.

Four wwstage 6c cgen quirks surfaced and are documented in dynout.ww's
header (two-level field-write through a pointer field, (scalar, str)
tuple returns, def : str, ≤6 arg calling convention).
This commit is contained in:
2026-05-11 12:47:36 +09:00
parent edfc4273f6
commit e217cd32d1
13 changed files with 3361 additions and 111 deletions

11
PLAN.md
View File

@@ -310,9 +310,14 @@ toolchain underneath).
`ww_ww build foo.ww` is now C-free at runtime: the driver invokes
the wwstage tools end-to-end. Cstage is still required at first-
checkout time (no checked-in stage-0 binary yet) and for examples
that exercise the C-only features still missing from the ww side:
ET_DYN dynamic linking in 6l (commit `ecf0a84`, used by `snake`).
checkout time (no checked-in stage-0 binary yet). ET_DYN dynamic
linking is also fully ported to the ww side (test 996 confirms
`6l_ww -L ... -l ...` is byte-identical to `6l` on snake); the one
remaining gap is that `ww_ww build`'s argv parser does not yet
forward `-L`/`-l` to the linker — `6l_ww` accepts them when invoked
directly, just not through the ww-side driver. Snake's Makefile
still drives the C `ww` for that reason; switching it to `6l_ww` +
explicit args works today.
Exit criterion 1 (bootstrap green) is met. Exit criterion 2 (delete
the C trees) is **deferred to v1.0**: removing `cmd/wwc/`, `cmd/6c/`,