build: recetas Cargo estáticas = crt-static + no-PIE (binarios autocontenidos)

Cierra el último bloqueo del boot que la corrida en QEMU destapó (runbook §8):
arje-zero/hammerd buildeaban DINÁMICOS contra musl (el rust de Alpine es dinámico
por defecto) → DT_NEEDED libc.musl-x86_64.so.1, y nuestro libc.so (musl shared con
zig cc) no exporta memcpy/memset/… → el loader falla y el init muere.

Fix golden-path: para link=static, RUSTFLAGS ahora fuerza
  -C target-feature=+crt-static -C relocation-model=static
⇒ binarios AUTOCONTENIDOS (musl dentro), ET_EXEC sin interpreter, como busybox:
sin libc.so, sin loader, sin el soname de Alpine. musl vuelve a --disable-shared
(no se necesita el loader). Boot en QEMU: usar -cpu Broadwell (el qemu64 default no
tiene el AVX que zig emite).

Validado por la corrida real: los 4 componentes buildan y el rootfs se sella; el
kernel arranca el initramfs y ejecuta arje-zero como PID 1. Falta rebuildear
hammerd/arje-zero con crt-static para cerrar el boot (cache-bust + rebuild).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-06-11 06:45:11 +00:00
co-authored by Claude Opus 4.8
parent 8d98a6053a
commit ce7b570a62
3 changed files with 34 additions and 3 deletions
+9 -1
View File
@@ -289,8 +289,14 @@ fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result<Phases> {
// CC (cc-rs) y como linker (RUSTFLAGS, target-agnóstico — el default sería
// cc/gcc, ausente en el sandbox zig-only).
let crt = match recipe.build.link {
// Estático = AUTOCONTENIDO: el rust de Alpine enlaza musl dinámico por
// defecto (deja `DT_NEEDED libc.musl-x86_64.so.1` y rompe el boot — el
// loader no resuelve memcpy/…; ver runbook §8). `+crt-static` mete musl
// dentro; `relocation-model=static` lo hace ET_EXEC sin interpreter (vía de
// oro de hammer, como busybox: sin libc.so, sin loader, sin soname).
LinkMode::Static => " -C target-feature=+crt-static -C relocation-model=static",
// Dinámico: apaga crt-static para poder dlopen (necesita el loader/musl en el rootfs).
LinkMode::Dynamic => " -C target-feature=-crt-static",
LinkMode::Static => "",
};
Some(format!(
"printf '%s\\n' '#!/bin/sh' 'for a do' \
@@ -433,6 +439,8 @@ commit = "deadbeef"
// el del wrapper saneador del triple alpine.
assert!(!c.contains("--offline --target"), "nativo: cargo sin --target ({c})");
assert!(c.contains("a=--target=x86_64-linux-musl"), "wrapper sanea el triple ({c})");
assert!(c.contains("target-feature=+crt-static"), "estático = autocontenido ({c})");
assert!(c.contains("relocation-model=static"), "no-PIE: ET_EXEC sin interpreter ({c})");
assert!(c.contains("CC=\"$PWD/.hammer-zig-cc\""), "CC = wrapper para cc-rs ({c})");
assert!(c.contains("RUSTFLAGS=\"-C linker=$PWD/.hammer-zig-cc"), "linker por RUSTFLAGS ({c})");
let i = p.install.unwrap();