toolchain: banner purge + WHY-only comment sweep (rule 8)

selfhost/, cmd/, internal/ join the tree-wide sweep: every section
banner dies (91 selfhost + the cmd C-style dividers -> 0); narration
and stale contracts deleted (pre-#22 bundler notes, retired
single-PT_LOAD and no-archive claims, superseded ABI tables); every
ref/harec/qbe cite, task cite, encoding/ELF contract, and rule-10
twin pointer kept; lost lifetime/rationale lines restored where the
sweep over-cut (elf_globals ownership, kwtab linear-scan). Comment-
only proven: all five wwstage tool binaries byte-identical across
the sweep; test-commit, test-byteid (161+1399, 0 pinned-divergent),
and test-bootstrap (fixed point + 991-995 byte-id) all exit 0.
The read-through banked 66 latent-bug leads (checkpoint).
This commit is contained in:
2026-08-08 23:14:03 +09:00
parent 83f5956df2
commit 62b9d20383
60 changed files with 232 additions and 1045 deletions

View File

@@ -1,11 +1,7 @@
/*
* dynout.c — emit a dynamic-linked ELF executable.
*
* The shape we produce is the simplest valid one: PT_INTERP +
* PT_DYNAMIC + DT_BIND_NOW so the loader resolves every PLT slot at
* startup (no lazy binding, no PLT0 trampoline). Symbol versioning
* is omitted; modern glibc tolerates unversioned references by
* binding to each symbol's "default" version. SysV .hash, not
* startup (no lazy binding, no PLT0 trampoline). SysV .hash, not
* .gnu.hash. Non-PIE, fixed base.
*
* File layout:
@@ -31,7 +27,6 @@
#include <stdlib.h>
#include <string.h>
/* ELF constants */
#define ET_EXEC 2
#define EM_X86_64 62
#define EV_CURRENT 1
@@ -127,7 +122,6 @@ elf_hash(const char *name)
return h;
}
/* Patch a 4-byte little-endian field in `buf` at offset `off`. */
static void
poke32(u8 *buf, u64 off, u32 v)
{
@@ -151,8 +145,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
const int N = l->dyn_n;
/* ---- Pass 1: collect dynamic symbol names + .dynstr layout ---- */
/* dynstr layout: [0]='\0', then DT_NEEDED soname strings, then
* one symbol name per dynamic Lsym. We index dyn syms by
* plt_idx (assigned in l_resolve). Build an array sorted by
@@ -189,7 +181,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
}
}
/* Build .dynstr in a growable buffer. */
u8 *dynstr = NULL;
u64 dynstr_cap = 0, dynstr_len = 0;
#define DSTR_PUT(s) do { \
@@ -216,9 +207,7 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
DSTR_PUT(dynsyms[i]->name);
}
/* ---- Versioning: group dyn syms by (lib, version) ----
*
* For every sym whose dyn_version is non-NULL, there's a
/* For every sym whose dyn_version is non-NULL, there's a
* Vernaux record under that lib's Verneed. The vna_other
* value (assigned starting at 2; 1 is reserved for "global,
* unversioned") becomes that sym's .gnu.version entry.
@@ -263,13 +252,11 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
n_vlibs++;
}
/* Assign vna_other indices starting at 2. */
u16 next_vna = 2;
for (int i = 0; i < n_vlibs; i++)
for (int k = 0; k < vlibs[i].n_versions; k++)
vlibs[i].versions[k].vna_other = next_vna++;
/* Add version name strings to .dynstr. */
for (int i = 0; i < n_vlibs; i++) {
for (int k = 0; k < vlibs[i].n_versions; k++) {
vlibs[i].versions[k].dynstr_off = (u32)dynstr_len;
@@ -301,8 +288,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
}
}
/* ---- Pass 2: compute byte sizes of every section ---- */
const u64 ehdr_sz = sizeof(Ehdr);
const int n_phdrs = 4;
const u64 phdr_sz = (u64)n_phdrs * sizeof(Phdr);
@@ -343,8 +328,7 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
const u64 ndyn = (u64)nsos + 11 + (with_ver ? 3 : 0);
const u64 dynamic_sz = ndyn * sizeof(Dyn64);
/* ---- Pass 3: assign file offsets and virtual addresses ----
* Everything from the Ehdr through .text+.plt is in the R+X
/* Everything from the Ehdr through .text+.plt is in the R+X
* load segment at base+0..text_end. .got.plt and .dynamic land
* in the R+W segment at the next page boundary. */
@@ -409,9 +393,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
const u64 data_file_len = l->datalen - bsslen;
const u64 file_data_end = data_off + data_file_len;
/* ---- Pass 4: build each section into a buffer ---- */
/* .dynsym */
Sym64 *dynsym = calloc((size_t)nsyms_total, sizeof *dynsym);
for (int i = 0; i < N; i++) {
Sym64 *e = &dynsym[1 + i];
@@ -438,7 +419,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
}
/* elf_hash is also used by .gnu.version_r for vna_hash below. */
/* .rela.plt */
Rela64 *relaplt = calloc((size_t)N, sizeof *relaplt);
for (int i = 0; i < N; i++) {
relaplt[i].r_offset = gotplt_va + (3 + (u64)i) * 8;
@@ -522,7 +502,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
}
/* [3..3+N-1] left zero; loader fills via R_X86_64_JUMP_SLOT. */
/* .dynamic */
Dyn64 *dynamic = calloc((size_t)ndyn, sizeof *dynamic);
{
int k = 0;
@@ -559,9 +538,9 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
}
}
/* ---- Pass 5: patch .text relocations targeting dynamic syms ---
* The site is the existing PC32/PLT32 displacement field. Target
* is the address of the symbol's PLT stub. */
/* Patch .text relocations targeting dynamic syms: the site is
* the existing PC32/PLT32 displacement field, the target the
* address of the symbol's PLT stub. */
for (Lrel *r = l->rels; r; r = r->next) {
if (r->sym == NULL || !r->sym->is_dyn) continue;
if (r->kind != R_X86_64_PC32 && r->kind != R_X86_64_PLT32) {
@@ -579,8 +558,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
poke32(l->text, r->off, (u32)(i32)disp);
}
/* ---- Pass 6: emit ---- */
Ehdr eh = {0};
memcpy(eh.e_ident, "\x7f""ELF", 4);
eh.e_ident[4] = ELFCLASS64;
@@ -625,7 +602,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
ph[1].p_memsz = file_end - gotplt_off;
ph[1].p_align = page;
/* PT_INTERP. */
ph[2].p_type = PT_INTERP;
ph[2].p_flags = PF_R;
ph[2].p_offset = interp_off;
@@ -635,7 +611,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
ph[2].p_memsz = interp_sz;
ph[2].p_align = 1;
/* PT_DYNAMIC. */
ph[3].p_type = PT_DYNAMIC;
ph[3].p_flags = PF_R | PF_W;
ph[3].p_offset = dynamic_off;
@@ -648,7 +623,6 @@ l_emit_dyn_elf(Lnk *l, FILE *f, u64 base, u64 entry)
fwrite(&eh, 1, sizeof eh, f);
fwrite(ph, 1, sizeof ph, f);
/* helper: pad to absolute offset `to` */
#define PAD_TO(to) do { \
long _here = ftell(f); \
for (long _i = _here; _i < (long)(to); _i++) fputc(0, f); \