From 7e41ffd0e66026921c5caf71a78de36d41143a4c Mon Sep 17 00:00:00 2001 From: Sergio Date: Fri, 11 Sep 2026 02:00:51 +0000 Subject: [PATCH] =?UTF-8?q?SDD=2028=20=C2=A76.5:=20el=20muro=20derribado?= =?UTF-8?q?=20=E2=80=94=20de=2023=20binarios=20inertes=20a=201,=20y=20sin?= =?UTF-8?q?=20mover=20un=20ArtifactHash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Elegidas las salidas 1 y 2 del §6.4; hecha la 1, que resultó más barata de lo que parecía y desbloquea la 2 en vez de competir con ella. `musl-shared` publica `/usr/lib/libc.so` + `/lib/ld-musl-x86_64.so.1`. Como variante y no tocando la canónica: `musl` es Stage 1 y su `of_tree` es el baseline del selfhost. Control: `takana hash recipes/musl.toml` sigue en `b3:ce952f72…`. Y `musl` no es dep de nadie ⇒ cero re-hasheo del corpus. En la caja: `sh: python3: not found` → `Python 3.12.10`. De 23 inertes quedó **1**, `sqlite3`, que pedía `libz.so.1`; `zlib-shared` ya estaba sellado y sólo faltaba declararla en `base`. La salida 2 (python/perl estáticos) sigue viva pero deja de ser urgente: con el cargador publicado el sistema ya no cuelga del rootfs del lab. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01RomoxEGZUhaT4pob1QSX5x --- docs/28-servidor-de-produccion.md | 45 +++++++++++++++++++++++++++++++ docs/state/targets.toml | 6 +++++ 2 files changed, 51 insertions(+) diff --git a/docs/28-servidor-de-produccion.md b/docs/28-servidor-de-produccion.md index 3c211bbd..b79c0817 100644 --- a/docs/28-servidor-de-produccion.md +++ b/docs/28-servidor-de-produccion.md @@ -582,6 +582,51 @@ Es decisión de ADR, y de las que conviene tomar mirando también el [SDD 27 §4 las dos preguntas —«¿el cliente reproduce o hidrata?» y «¿el cliente puede correr lo que le mandamos?»— son la misma pregunta sobre qué es un sistema takana **sin laboratorio**. +### 6.5 ✅ El muro, derribado: el corpus publica su propio cargador *(2026-09-11)* + +De las tres salidas del §6.4 el usuario eligió la 1 y la 2. Hecha la **1**, que resultó ser más barata +de lo que parecía y desbloquea la 2 en vez de competir con ella. + +**`recipes/musl-shared.toml`** — variante dinámica de musl que publica `/usr/lib/libc.so` (4,2 M) y +`/lib/ld-musl-x86_64.so.1`. En musl el cargador Y la libc son el mismo objeto. + +**Por qué una variante y no `--enable-shared` en la canónica**, con su control: `musl` es componente +de **Stage 1** y su `of_tree` es el baseline de `selfhost-verify`. Tocarla obliga a rehacer ese +baseline a propósito. Con el patrón `*-shared` —que el corpus ya usa 23 veces— la canónica no se +mueve: `takana hash recipes/musl.toml` sigue dando `b3:ce952f72…`, el mismo sellado de Stage 1. Y +además **`musl` no es dep de nadie** (medido: sólo de sí misma; el enlace estático lo resuelve el +musl que trae zig), así que esto **suma sin mover un solo ArtifactHash del corpus**. + +#### ⚠ Y hubo que cambiar de compilador, medido + +Con `zig-cc` el `libc.so` sale con **1586 símbolos dinámicos** contra los **1654** del musl de Alpine, +y los **68 que faltan son exactamente** los que musl implementa en ensamblador x86_64 — `memset`, +`memcpy`, `memmove`, `memcmp`, `strlen` y toda la familia matemática (`ceil floor sqrt fmod exp log +sin cos tan fma round trunc`) — más los `__stack_chk_*`. + +No es que no se compilen: en el `libc.a` del musl canónico **están**. Lo que pasa es que **zig los +resuelve con su propio musl y los deja `FUNC LOCAL HIDDEN` de tamaño 0**, fuera de la tabla dinámica. +El síntoma es un cargador que arranca, reloca y muere con `memset: symbol not found` — que se lee +como «el binario está roto», no como «a la libc le faltan símbolos». + +Con `compiler = "gcc"`: **1651 símbolos**, `memset` y `ceil` presentes. + +#### El resultado, en la caja + +| antes | después | +|---|---| +| `sh: python3: not found` (con `command -v` contestando `/usr/bin/python3`) | `Python 3.12.10` | +| 23 binarios inertes de 726 | **1** | + +`perl 5.040002`, `readelf`/`objdump`/`nm` (GNU Binutils 2.45.1) y el resto corren. El único que +quedaba era **`sqlite3`**, con `Error loading shared library libz.so.1`: la zlib canónica también es +`--disable-shared` y nadie publicaba ese soname. `zlib-shared` ya existía sellado en el corpus — +sólo faltaba declararla en `base`. + +**La salida 2 (python/perl estáticos) sigue viva y ahora es opcional, no urgente**: con el cargador +publicado el sistema ya no depende del rootfs del lab. Estático seguiría siendo mejor (un binario +menos que puede quedar colgado de un soname), pero es un frente propio y ya no bloquea la mudanza. + ### 6.2 Lo que la mudanza tiene que producir, además de la mudanza El usuario lo pidió explícito: **que este experimento saque recetas y las pruebe**. La caja vieja es diff --git a/docs/state/targets.toml b/docs/state/targets.toml index 237b4391..bc7da54e 100644 --- a/docs/state/targets.toml +++ b/docs/state/targets.toml @@ -40,6 +40,12 @@ paquetes = [ # instrumental del proyecto. El síntoma era `sh: python3: not found` con `command -v python3` # contestando `/usr/bin/python3`: no falta, no arranca. Ver SDD 28 §6.4. "musl-shared", + # `zlib-shared` (2026-09-11): el único hueco que quedó tras publicar el cargador. Con + # `musl-shared`, 22 de los 23 binarios inertes de la imagen del servidor pasaron a correr; el 23º + # era `sqlite3`, que muere con `Error loading shared library libz.so.1`. La zlib canónica es + # `--disable-shared` y ningún artefacto publicaba ese soname — otra vez el rootfs del lab tapando + # el agujero. La variante ya existía en el corpus; sólo faltaba declararla. + "zlib-shared", ] [perfil.cli]