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,10 +1,7 @@
/*
* a.h — w6a-private header. Modelled on Plan 9 cmd/6a/a.h, trimmed
* to the instruction subset that w6c emits.
*
* w6a is line-oriented and has no preprocessor: each non-blank, non-
* label line is one instruction. We read the whole file into a list
* of `Aprog`s, then encode and emit ELF64.
* Modelled on Plan 9 cmd/6a/a.h, trimmed to the instruction subset
* that w6c emits. Line-oriented, no preprocessor: each non-blank,
* non-label line is one instruction.
*/
#ifndef SIX_A_H
#define SIX_A_H
@@ -69,17 +66,14 @@ struct Areloc {
};
struct Asm {
/* parser state */
const char *file;
const char *src;
u64 srclen;
u64 pos;
int line;
/* program list */
Aprog *head, *tail;
/* output text section */
u8 *text;
u64 textcap, textlen;
@@ -89,7 +83,6 @@ struct Asm {
u8 *data;
u64 datacap, datalen;
/* symbols */
Asym *syms;
Areloc *relocs;

View File

@@ -1,8 +1,4 @@
/*
* asm.c — encode the parsed Aprog list into amd64 machine bytes,
* appending to Asm.text. Relocations for CALL/branch targets that
* resolve to externals are queued in Asm.relocs.
*
* Encoding subset: the instructions cgen emits today. Operand shapes
* we accept:
* MOVQ $imm, reg — C7 /0 imm32 (REX.W) [imm fits in i32]
@@ -95,8 +91,6 @@ a_addreloc_data(Asm *a, u64 off, int kind, Asym *s, i64 add)
a->relocs = r;
}
/* ------ register codes ------------------------------------------- */
/* low 3 bits of register encoding */
static int
rcode(int r)
@@ -137,14 +131,12 @@ is_xmm(int r)
return r >= D_X0 && r <= D_X15;
}
/* ModR/M byte */
static u8
modrm(int mod, int reg, int rm)
{
return (u8)(((mod & 3) << 6) | ((reg & 7) << 3) | (rm & 7));
}
/* emit REX with W=1 plus optional R/B for high regs */
static void
emit_rex(Asm *a, int regbit, int rmbit, int w)
{
@@ -155,9 +147,7 @@ emit_rex(Asm *a, int regbit, int rmbit, int w)
if (b != 0x40 || w) a_emit_byte(a, b);
}
/* encode mod/disp for [base+disp]; returns 0 on ok.
* Special-cases SP (needs SIB) and BP (forces disp).
*/
/* Special-cases SP (needs SIB) and BP (forces disp). */
static void
emit_modrm_mem(Asm *a, int reg_field, int base, i64 disp)
{
@@ -191,7 +181,6 @@ encode_rr(Asm *a, u8 opcode, int src, int dst)
a_emit_byte(a, modrm(3, rcode(src), rcode(dst)));
}
/* MOVQ src reg → mem(base, disp). opcode = 0x89 */
static void
encode_rm(Asm *a, u8 opcode, int src_reg, int base, i64 disp)
{
@@ -200,7 +189,6 @@ encode_rm(Asm *a, u8 opcode, int src_reg, int base, i64 disp)
emit_modrm_mem(a, rcode(src_reg), base, disp);
}
/* MOVQ mem(base, disp) → reg. opcode = 0x8B */
static void
encode_mr(Asm *a, u8 opcode, int dst_reg, int base, i64 disp)
{
@@ -250,7 +238,7 @@ sse_mr_load(Asm *a, u8 prefix, u8 op2, int reg_op, int base, i64 disp)
emit_modrm_mem(a, rcode(reg_op), base, disp);
}
/* like sse_mr_load but encoded with REX.W (used by CVTTSD2SI / CVTSI2SD
/* like sse_rr but encoded with REX.W (used by CVTTSD2SI / CVTSI2SD
* which target/source 64-bit integer regs) */
static void
sse_rr_w(Asm *a, u8 prefix, u8 op2, int reg_op, int rm_op)
@@ -262,8 +250,6 @@ sse_rr_w(Asm *a, u8 prefix, u8 op2, int reg_op, int rm_op)
a_emit_byte(a, modrm(3, rcode(reg_op), rcode(rm_op)));
}
/* ------ second-pass helper: resolve labels to addresses ---------- */
static u64
resolve_label(Asm *a, const char *name)
{
@@ -281,8 +267,6 @@ label_defined(Asm *a, const char *name)
return 0;
}
/* ------ first pass: encode ---------------------------------------- */
/* For local labels, we record a "fixup" — an offset in .text that
* needs to be patched once the label is resolved at end of pass. */
typedef struct Fixup Fixup;
@@ -307,10 +291,9 @@ int
a_encode(Asm *a)
{
fixups = NULL;
const char *cur_text = NULL; /* current TEXT name */
const char *cur_text = NULL;
(void)cur_text;
for (Aprog *p = a->head; p; p = p->link) {
/* Define any pending label at the current PC */
if (p->label) {
Asym *s = a_intern(a, p->label);
s->defined = 1;
@@ -800,7 +783,6 @@ a_encode(Asm *a)
/* R_X86_64_PLT32 (4); addend -4 */
a_addreloc(a, reloff, 4, s, -4);
} else if (p->to.type == D_BRANCH) {
/* local call to a label */
a_emit_byte(a, 0xE8);
add_fixup(a->textlen, p->to.sym);
a_emit_u32(a, 0);
@@ -846,7 +828,6 @@ a_encode(Asm *a)
}
}
/* second pass: patch fixups */
for (Fixup *f = fixups; f; f = f->next) {
if (!label_defined(a, f->label)) {
fprintf(stderr, "w6a: undefined label '%s'\n", f->label);

View File

@@ -1,8 +1,3 @@
/*
* lex.c — character-level helpers for w6a's line-oriented parser.
* The parser itself lives in parse.c; here we keep the tokenisers
* for identifiers and numbers so parse.c stays focused on syntax.
*/
#include "a.h"
#include <ctype.h>
#include <stdlib.h>

View File

@@ -1,6 +1,3 @@
/*
* w6a — amd64 assembler driver. Read .s, parse, encode, emit ELF .o.
*/
#include "a.h"
#include <stdio.h>
#include <stdlib.h>

View File

@@ -1,6 +1,4 @@
/*
* obj.c — emit a tiny ELF64 relocatable object.
*
* Layout (in file order):
* [0] ELF header
* [1] Section .text (program bytes)
@@ -24,7 +22,6 @@
#include <string.h>
#include <stdio.h>
/* ELF constants */
#define ELFMAG "\x7f""ELF"
#define ELFCLASS64 2
#define ELFDATA2LSB 1
@@ -54,7 +51,6 @@
#define R_X86_64_PLT32 4
#define ELF64_R_INFO(s,t) (((u64)(s) << 32) | ((u64)(t) & 0xffffffff))
/* growable byte buffer */
typedef struct Buf Buf;
struct Buf { u8 *p; size_t n, cap; };
@@ -157,10 +153,9 @@ a_emit_elf(Asm *a, FILE *f)
bput(&sym, &z, sizeof z);
}
/* Build symbols (defined = global; undefined = global UND). Data
* symbols carry STT_OBJECT and st_shndx=SH_DATA; everything else
* keeps the legacy STT_FUNC/SH_TEXT shape so non-DATAW outputs
* stay byte-identical. */
/* Data symbols carry STT_OBJECT and st_shndx=SH_DATA; everything
* else keeps the legacy STT_FUNC/SH_TEXT shape so non-DATAW
* outputs stay byte-identical. */
int idx = 1;
for (Asym *s = a->syms; s; s = s->next) {
Sym64 e = {0};
@@ -193,7 +188,6 @@ a_emit_elf(Asm *a, FILE *f)
bput(r->section == 1 ? &relad : &rela, &re, sizeof re);
}
/* Layout offsets in the file */
u64 off = sizeof(Ehdr);
u64 off_text = off; off += a->textlen;
u64 off_rela = off; off += rela.n;
@@ -202,7 +196,6 @@ a_emit_elf(Asm *a, FILE *f)
u64 off_sym = off; off += sym.n;
u64 off_str = off; off += str.n;
u64 off_shstr= off; off += shstr.n;
/* align to 8 */
while (off % 8) off++;
u64 off_shdr = off;
const int NSECT = has_data

View File

@@ -1,6 +1,4 @@
/*
* parse.c — line-oriented parser for the asm subset emitted by w6c.
*
* Grammar:
* line := blank | comment | label | text | instr
* blank := /^\s*$/
@@ -52,7 +50,6 @@ a_intern(Asm *a, const char *name)
return s;
}
/* ------------------------------------------------------------------ */
/* line iterator: returns the next line as a NUL-terminated buffer in
* line/llen pointers, advances pos. Returns 0 on EOF.
*/
@@ -70,7 +67,6 @@ nextline(Asm *a, char **line, size_t *llen, char *buf, size_t bufsz)
return 1;
}
/* skip leading whitespace */
static const char *
skipws(const char *p)
{
@@ -168,7 +164,6 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
return 0;
}
/* (REG) form */
if (*s == '(') {
s++;
char rbuf[8] = {0};
@@ -183,7 +178,6 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
return 0;
}
/* number(REG) form, or label form, or REG */
const char *p = s;
int sign = 1;
if (*p == '-') { sign = -1; p++; }
@@ -208,7 +202,6 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
return 0;
}
/* IDENT — register or symbol-or-label */
if (a_isidstart((unsigned char)*s)) {
char buf[256] = {0};
int n = 0;
@@ -226,7 +219,6 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
s = end;
}
/* ID(SB) means external symbol */
if (*s == '(') {
char rbuf[8] = {0};
int rn = 0;
@@ -253,7 +245,6 @@ parse_operand(Asm *a, const char *s, Aoperand *out)
out->type = r;
return 0;
}
/* otherwise it's a branch target */
out->type = D_BRANCH;
out->sym = strdup(buf);
return 0;
@@ -281,7 +272,6 @@ a_parse(Asm *a)
continue;
}
/* label? */
if (a_isidstart((unsigned char)*p) && line[0] != '\t') {
const char *q = p;
while (a_isidcont((unsigned char)*q)) q++;
@@ -308,7 +298,6 @@ a_parse(Asm *a)
}
}
/* TEXT or instruction */
const char *m = p;
char mnem[16] = {0};
int n = 0;
@@ -332,7 +321,6 @@ a_parse(Asm *a)
const char *rest = m;
if (op == A_TEXT) {
/* TEXT name,$framesize */
char nbuf[256] = {0};
int nn = 0;
while (*m && *m != ',' && nn < 255) nbuf[nn++] = *m++;
@@ -363,7 +351,6 @@ a_parse(Asm *a)
prg->nbytes = 0;
} else {
m++;
/* parse escapes into a fresh buffer */
size_t cap = 32, len = 0;
u8 *buf = malloc(cap);
while (*m && *m != '"') {
@@ -398,7 +385,6 @@ a_parse(Asm *a)
prg->nbytes = len;
}
} else {
/* split rest at top-level comma */
const char *comma = NULL;
for (const char *q = rest; *q; q++)
if (*q == ',' && comma == NULL) comma = q;